diff --git a/compiler/src/prog8/ast/AstToSourceCode.kt b/compiler/src/prog8/ast/AstToSourceCode.kt index 5f1d151bf..66cdf6245 100644 --- a/compiler/src/prog8/ast/AstToSourceCode.kt +++ b/compiler/src/prog8/ast/AstToSourceCode.kt @@ -283,14 +283,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): } override fun visit(assignment: Assignment) { - if(assignment is VariableInitializationAssignment) { - val targetVar = assignment.target.identifier?.targetVarDecl(program.namespace) - if(targetVar?.struct != null) { - // skip STRUCT init assignments - return - } - } - assignment.target.accept(this) if (assignment.aug_op != null) output(" ${assignment.aug_op} ") diff --git a/compiler/src/prog8/ast/base/Extensions.kt b/compiler/src/prog8/ast/base/Extensions.kt index 1d1e95dac..700f97578 100644 --- a/compiler/src/prog8/ast/base/Extensions.kt +++ b/compiler/src/prog8/ast/base/Extensions.kt @@ -7,10 +7,6 @@ import prog8.compiler.CompilationOptions import prog8.optimizer.FlattenAnonymousScopesAndNopRemover -// the name of the subroutine that should be called for every block to initialize its variables -internal const val initvarsSubName = "prog8_init_vars" - - internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: ErrorReporter) { val checker = AstChecker(this, compilerOptions, errors) checker.visit(this) @@ -23,7 +19,7 @@ internal fun Program.moveAnonScopeVarsToSubroutine(errors: ErrorReporter) { } internal fun Program.reorderStatements() { - val initvalueCreator = VarInitValueCreator(this) + val initvalueCreator = AddressOfInserter(this) initvalueCreator.visit(this) initvalueCreator.applyModifications() diff --git a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt b/compiler/src/prog8/ast/processing/AddressOfInserter.kt similarity index 75% rename from compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt rename to compiler/src/prog8/ast/processing/AddressOfInserter.kt index f6f562993..0e9bd3165 100644 --- a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt +++ b/compiler/src/prog8/ast/processing/AddressOfInserter.kt @@ -11,17 +11,14 @@ import prog8.functions.BuiltinFunctions import prog8.functions.FSignature -internal class VarInitValueCreator(val program: Program): AstWalker() { - // For VarDecls that declare an initialization value: - // add an assignment to set this initial value explicitly. - // This makes sure the variables get reset to the intended value on a next run of the program. - // Also takes care to insert AddressOf (&) expression where required (string params to a UWORD function param etc). +internal class AddressOfInserter(val program: Program): AstWalker() { + // Insert AddressOf (&) expression where required (string params to a UWORD function param etc). // TODO join this into the StatementReorderer? - // TODO actually I think the code generator should take care of this entirely, and this step should be removed from the ast modifications... override fun after(decl: VarDecl, parent: Node): Iterable { if(decl.isArray && decl.value==null) { // array datatype without initialization value, add list of zeros + // TODO let the code generator take care of this? val arraysize = decl.arraysize!!.size()!! val zero = decl.asDefaultValueDecl(decl).value!! return listOf(IAstModification.SetExpression( // can't use replaceNode here because value is null @@ -32,30 +29,8 @@ internal class VarInitValueCreator(val program: Program): AstWalker() { decl)) } - val declvalue = decl.value - if(decl.type == VarDeclType.VAR && declvalue != null && decl.datatype in NumericDatatypes) { - val value = - if(declvalue is NumericLiteralValue) - declvalue.cast(decl.datatype) - else - declvalue - val identifierName = listOf(decl.name) - val initvalue = VariableInitializationAssignment( - AssignTarget(null, - IdentifierReference(identifierName, decl.position), - null, null, decl.position), - null, value, decl.position - ) - val zero = decl.asDefaultValueDecl(decl).value!! - return listOf( - IAstModification.Insert(decl, initvalue, parent), - IAstModification.ReplaceNode( - declvalue, - zero, - decl - ) - ) - } + if(decl.value!=null && decl.type==VarDeclType.VAR && !decl.isArray) + decl.definingBlock().initialValues += decl return emptyList() } diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index ce5b89e82..25c58c2ed 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -40,7 +40,6 @@ internal class AstChecker(private val program: Program, is VarDecl -> true is InlineAssembly -> true is INameScope -> true - is VariableInitializationAssignment -> true is NopStatement -> true else -> false } diff --git a/compiler/src/prog8/ast/processing/StatementReorderer.kt b/compiler/src/prog8/ast/processing/StatementReorderer.kt index d1e3deb35..a04e4dd02 100644 --- a/compiler/src/prog8/ast/processing/StatementReorderer.kt +++ b/compiler/src/prog8/ast/processing/StatementReorderer.kt @@ -3,7 +3,6 @@ package prog8.ast.processing import prog8.ast.* import prog8.ast.base.DataType import prog8.ast.base.FatalAstException -import prog8.ast.base.initvarsSubName import prog8.ast.expressions.* import prog8.ast.statements.* @@ -108,21 +107,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi block.statements.addAll(0, directives) block.linkParents(block.parent) - // create subroutine that initializes the block's variables (if any) - val varInits = block.statements.withIndex().filter { it.value is VariableInitializationAssignment } - if(varInits.isNotEmpty()) { - val statements = varInits.map{it.value}.toMutableList() - val varInitSub = Subroutine(initvarsSubName, emptyList(), emptyList(), emptyList(), emptyList(), - emptySet(), null, false, statements, block.position) - varInitSub.keepAlways = true - varInitSub.linkParents(block) - block.statements.add(varInitSub) - - // remove the varinits from the block's statements - for(index in varInits.map{it.index}.reversed()) - block.statements.removeAt(index) - } - return super.visit(block) } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 202032609..3af07dac3 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -73,6 +73,7 @@ class Block(override val name: String, val idx = statements.indexOf(node) statements[idx] = replacement } + val initialValues = mutableListOf() // will be gathered by one of the Ast processing steps override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) @@ -373,11 +374,6 @@ open class Assignment(var target: AssignTarget, val aug_op : String?, var value: } } -// This is a special class so the compiler can see if the assignments are for initializing the vars in the scope, -// or just a regular assignment. It could optimize the initialization step from this. -class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, value: Expression, position: Position) - : Assignment(target, aug_op, value, position) - data class AssignTarget(val register: Register?, var identifier: IdentifierReference?, var arrayindexed: ArrayIndexedExpression?, diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index ca4f1d3f5..6b4e1ab16 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -126,11 +126,7 @@ internal class AsmGen(private val program: Program, out(" ldx #\$ff\t; init estack pointer") out(" ; initialize the variables in each block") - for (block in program.allBlocks()) { - val initVarsSub = block.statements.singleOrNull { it is Subroutine && it.name == initvarsSubName } - if(initVarsSub!=null) - out(" jsr ${block.name}.$initvarsSubName") - } + program.allBlocks().filter { it.initialValues.any() }.forEach { out(" jsr ${it.name}.prog8_init_vars") } out(" clc") when (zeropage.exitProgramStrategy) { @@ -175,6 +171,19 @@ internal class AsmGen(private val program: Program, stmts.forEach { translate(it) } subroutine.forEach { translateSubroutine(it as Subroutine) } + // if any global vars need to be initialized, generate a subroutine that does this + // it will be called from program init. + if(block.initialValues.isNotEmpty()) { + out("prog8_init_vars\t.proc\n") + block.initialValues.forEach { + val target = AssignTarget(null, IdentifierReference(listOf(it.scopedname), it.position), null, null, it.position) + val assign = Assignment(target, null, it.value!!, it.position) + assign.linkParents(it.parent) + assignmentAsmGen.translate(assign) + } + out(" rts\n .pend") + } + out(if("force_output" in block.options()) "\n\t.bend\n" else "\n\t.pend\n") } diff --git a/compiler/src/prog8/optimizer/CallGraph.kt b/compiler/src/prog8/optimizer/CallGraph.kt index f8994f38d..67201e736 100644 --- a/compiler/src/prog8/optimizer/CallGraph.kt +++ b/compiler/src/prog8/optimizer/CallGraph.kt @@ -7,7 +7,6 @@ import prog8.ast.Program import prog8.ast.base.DataType import prog8.ast.base.ParentSentinel import prog8.ast.base.VarDeclType -import prog8.ast.base.initvarsSubName import prog8.ast.expressions.FunctionCall import prog8.ast.expressions.IdentifierReference import prog8.ast.processing.IAstVisitor @@ -120,7 +119,7 @@ class CallGraph(private val program: Program) : IAstVisitor { override fun visit(subroutine: Subroutine) { if (Pair(subroutine.definingScope().name, subroutine.name) in alwaysKeepSubroutines - || subroutine.name == initvarsSubName || subroutine.definingModule().isLibraryModule) { + || subroutine.definingModule().isLibraryModule) { // make sure the entrypoint is mentioned in the used symbols addNodeAndParentScopes(subroutine) } diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 861f0bd4d..f82a51533 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -196,13 +196,14 @@ class AstVm(val program: Program, compilationTarget: String) { for (m in program.modules) { for (b in m.statements.filterIsInstance()) { for (s in b.statements.filterIsInstance()) { - if (s.name == initvarsSubName) { - try { - executeSubroutine(s, emptyList(), null) - } catch (x: LoopControlReturn) { - // regular return - } - } + TODO("initialize variable values") +// if (s.name == initvarsSubName) { +// try { +// executeSubroutine(s, emptyList(), null) +// } catch (x: LoopControlReturn) { +// // regular return +// } +// } } } } diff --git a/examples/test.p8 b/examples/test.p8 index e26f73a2a..09754ff88 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,9 +6,44 @@ main { sub start() { - c64scr.clear_screen('*',7) - c64.CHRIN() - c64scr.clear_screen('.',2) + ubyte ub1 + ubyte ub2 = 99 + uword uw1 + uword uw2 = 9999 + ubyte[5] array1 + ubyte[5] array2 = [22,33,44,55,66] + c64scr.print_ub(ub1) + c64.CHROUT(',') + c64scr.print_ub(ub2) + c64.CHROUT(',') + c64scr.print_uw(uw1) + c64.CHROUT(',') + c64scr.print_uw(uw2) + c64.CHROUT(',') + c64scr.print_ub(array1[0]) + c64.CHROUT(',') + c64scr.print_ub(array2[0]) + c64.CHROUT('\n') + + ub1++ + ub2++ + uw1++ + uw2++ + array1[0]++ + array2[0]++ + + c64scr.print_ub(ub1) + c64.CHROUT(',') + c64scr.print_ub(ub2) + c64.CHROUT(',') + c64scr.print_uw(uw1) + c64.CHROUT(',') + c64scr.print_uw(uw2) + c64.CHROUT(',') + c64scr.print_ub(array1[0]) + c64.CHROUT(',') + c64scr.print_ub(array2[0]) + c64.CHROUT('\n') } }