mirror of
https://github.com/irmen/prog8.git
synced 2025-02-21 10:29:03 +00:00
simplified handling of initial vardecl values in codegeneration
This commit is contained in:
parent
4fbdd6d570
commit
78feef9d59
@ -283,14 +283,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(assignment: Assignment) {
|
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)
|
assignment.target.accept(this)
|
||||||
if (assignment.aug_op != null)
|
if (assignment.aug_op != null)
|
||||||
output(" ${assignment.aug_op} ")
|
output(" ${assignment.aug_op} ")
|
||||||
|
@ -7,10 +7,6 @@ import prog8.compiler.CompilationOptions
|
|||||||
import prog8.optimizer.FlattenAnonymousScopesAndNopRemover
|
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) {
|
internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: ErrorReporter) {
|
||||||
val checker = AstChecker(this, compilerOptions, errors)
|
val checker = AstChecker(this, compilerOptions, errors)
|
||||||
checker.visit(this)
|
checker.visit(this)
|
||||||
@ -23,7 +19,7 @@ internal fun Program.moveAnonScopeVarsToSubroutine(errors: ErrorReporter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun Program.reorderStatements() {
|
internal fun Program.reorderStatements() {
|
||||||
val initvalueCreator = VarInitValueCreator(this)
|
val initvalueCreator = AddressOfInserter(this)
|
||||||
initvalueCreator.visit(this)
|
initvalueCreator.visit(this)
|
||||||
initvalueCreator.applyModifications()
|
initvalueCreator.applyModifications()
|
||||||
|
|
||||||
|
@ -11,17 +11,14 @@ import prog8.functions.BuiltinFunctions
|
|||||||
import prog8.functions.FSignature
|
import prog8.functions.FSignature
|
||||||
|
|
||||||
|
|
||||||
internal class VarInitValueCreator(val program: Program): AstWalker() {
|
internal class AddressOfInserter(val program: Program): AstWalker() {
|
||||||
// For VarDecls that declare an initialization value:
|
// Insert AddressOf (&) expression where required (string params to a UWORD function param etc).
|
||||||
// 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).
|
|
||||||
// TODO join this into the StatementReorderer?
|
// 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<IAstModification> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
if(decl.isArray && decl.value==null) {
|
if(decl.isArray && decl.value==null) {
|
||||||
// array datatype without initialization value, add list of zeros
|
// array datatype without initialization value, add list of zeros
|
||||||
|
// TODO let the code generator take care of this?
|
||||||
val arraysize = decl.arraysize!!.size()!!
|
val arraysize = decl.arraysize!!.size()!!
|
||||||
val zero = decl.asDefaultValueDecl(decl).value!!
|
val zero = decl.asDefaultValueDecl(decl).value!!
|
||||||
return listOf(IAstModification.SetExpression( // can't use replaceNode here because value is null
|
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))
|
decl))
|
||||||
}
|
}
|
||||||
|
|
||||||
val declvalue = decl.value
|
if(decl.value!=null && decl.type==VarDeclType.VAR && !decl.isArray)
|
||||||
if(decl.type == VarDeclType.VAR && declvalue != null && decl.datatype in NumericDatatypes) {
|
decl.definingBlock().initialValues += decl
|
||||||
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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
@ -40,7 +40,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
is VarDecl -> true
|
is VarDecl -> true
|
||||||
is InlineAssembly -> true
|
is InlineAssembly -> true
|
||||||
is INameScope -> true
|
is INameScope -> true
|
||||||
is VariableInitializationAssignment -> true
|
|
||||||
is NopStatement -> true
|
is NopStatement -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package prog8.ast.processing
|
|||||||
import prog8.ast.*
|
import prog8.ast.*
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.FatalAstException
|
import prog8.ast.base.FatalAstException
|
||||||
import prog8.ast.base.initvarsSubName
|
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
|
|
||||||
@ -108,21 +107,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
|||||||
block.statements.addAll(0, directives)
|
block.statements.addAll(0, directives)
|
||||||
block.linkParents(block.parent)
|
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)
|
return super.visit(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ class Block(override val name: String,
|
|||||||
val idx = statements.indexOf(node)
|
val idx = statements.indexOf(node)
|
||||||
statements[idx] = replacement
|
statements[idx] = replacement
|
||||||
}
|
}
|
||||||
|
val initialValues = mutableListOf<VarDecl>() // will be gathered by one of the Ast processing steps
|
||||||
|
|
||||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: IAstVisitor) = 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?,
|
data class AssignTarget(val register: Register?,
|
||||||
var identifier: IdentifierReference?,
|
var identifier: IdentifierReference?,
|
||||||
var arrayindexed: ArrayIndexedExpression?,
|
var arrayindexed: ArrayIndexedExpression?,
|
||||||
|
@ -126,11 +126,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
out(" ldx #\$ff\t; init estack pointer")
|
out(" ldx #\$ff\t; init estack pointer")
|
||||||
|
|
||||||
out(" ; initialize the variables in each block")
|
out(" ; initialize the variables in each block")
|
||||||
for (block in program.allBlocks()) {
|
program.allBlocks().filter { it.initialValues.any() }.forEach { out(" jsr ${it.name}.prog8_init_vars") }
|
||||||
val initVarsSub = block.statements.singleOrNull { it is Subroutine && it.name == initvarsSubName }
|
|
||||||
if(initVarsSub!=null)
|
|
||||||
out(" jsr ${block.name}.$initvarsSubName")
|
|
||||||
}
|
|
||||||
|
|
||||||
out(" clc")
|
out(" clc")
|
||||||
when (zeropage.exitProgramStrategy) {
|
when (zeropage.exitProgramStrategy) {
|
||||||
@ -175,6 +171,19 @@ internal class AsmGen(private val program: Program,
|
|||||||
stmts.forEach { translate(it) }
|
stmts.forEach { translate(it) }
|
||||||
subroutine.forEach { translateSubroutine(it as Subroutine) }
|
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")
|
out(if("force_output" in block.options()) "\n\t.bend\n" else "\n\t.pend\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import prog8.ast.Program
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.ParentSentinel
|
import prog8.ast.base.ParentSentinel
|
||||||
import prog8.ast.base.VarDeclType
|
import prog8.ast.base.VarDeclType
|
||||||
import prog8.ast.base.initvarsSubName
|
|
||||||
import prog8.ast.expressions.FunctionCall
|
import prog8.ast.expressions.FunctionCall
|
||||||
import prog8.ast.expressions.IdentifierReference
|
import prog8.ast.expressions.IdentifierReference
|
||||||
import prog8.ast.processing.IAstVisitor
|
import prog8.ast.processing.IAstVisitor
|
||||||
@ -120,7 +119,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
|||||||
|
|
||||||
override fun visit(subroutine: Subroutine) {
|
override fun visit(subroutine: Subroutine) {
|
||||||
if (Pair(subroutine.definingScope().name, subroutine.name) in alwaysKeepSubroutines
|
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
|
// make sure the entrypoint is mentioned in the used symbols
|
||||||
addNodeAndParentScopes(subroutine)
|
addNodeAndParentScopes(subroutine)
|
||||||
}
|
}
|
||||||
|
@ -196,13 +196,14 @@ class AstVm(val program: Program, compilationTarget: String) {
|
|||||||
for (m in program.modules) {
|
for (m in program.modules) {
|
||||||
for (b in m.statements.filterIsInstance<Block>()) {
|
for (b in m.statements.filterIsInstance<Block>()) {
|
||||||
for (s in b.statements.filterIsInstance<Subroutine>()) {
|
for (s in b.statements.filterIsInstance<Subroutine>()) {
|
||||||
if (s.name == initvarsSubName) {
|
TODO("initialize variable values")
|
||||||
try {
|
// if (s.name == initvarsSubName) {
|
||||||
executeSubroutine(s, emptyList(), null)
|
// try {
|
||||||
} catch (x: LoopControlReturn) {
|
// executeSubroutine(s, emptyList(), null)
|
||||||
// regular return
|
// } catch (x: LoopControlReturn) {
|
||||||
}
|
// // regular return
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,44 @@
|
|||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
c64scr.clear_screen('*',7)
|
ubyte ub1
|
||||||
c64.CHRIN()
|
ubyte ub2 = 99
|
||||||
c64scr.clear_screen('.',2)
|
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')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user