mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 22:30:46 +00:00
fixed some node update issues in Modifying Ast visitor
This commit is contained in:
parent
fed020825a
commit
b7502c7eaa
@ -247,8 +247,8 @@ class BinaryExpression(var left: Expression, var operator: String, var right: Ex
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayIndexedExpression(val identifier: IdentifierReference,
|
||||
var arrayspec: ArrayIndex,
|
||||
class ArrayIndexedExpression(var identifier: IdentifierReference,
|
||||
val arrayspec: ArrayIndex,
|
||||
override val position: Position) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
override fun linkParents(parent: Node) {
|
||||
@ -304,7 +304,7 @@ class TypecastExpression(var expression: Expression, var type: DataType, val imp
|
||||
}
|
||||
}
|
||||
|
||||
data class AddressOf(val identifier: IdentifierReference, override val position: Position) : Expression() {
|
||||
data class AddressOf(var identifier: IdentifierReference, override val position: Position) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
@ -753,6 +753,13 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
else -> throw FatalAstException("requires a reference value")
|
||||
}
|
||||
}
|
||||
|
||||
fun withPrefixedName(nameprefix: String): IdentifierReference {
|
||||
val prefixed = nameInSource.dropLast(1) + listOf(nameprefix+nameInSource.last())
|
||||
val new = IdentifierReference(prefixed, position)
|
||||
new.parent = parent
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionCall(override var target: IdentifierReference,
|
||||
|
@ -370,8 +370,9 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
val assignment = assignTarget.parent as Statement
|
||||
if (assignTarget.identifier != null) {
|
||||
val targetName = assignTarget.identifier.nameInSource
|
||||
val targetIdentifier = assignTarget.identifier
|
||||
if (targetIdentifier != null) {
|
||||
val targetName = targetIdentifier.nameInSource
|
||||
val targetSymbol = program.namespace.lookup(targetName, assignment)
|
||||
when (targetSymbol) {
|
||||
null -> {
|
||||
|
@ -166,30 +166,32 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
checkResult.add(SyntaxError("register loop variables have a fixed implicit datatype", forLoop.position))
|
||||
if(forLoop.loopRegister == Register.X)
|
||||
printWarning("writing to the X register is dangerous, because it's used as an internal pointer", forLoop.position)
|
||||
} else if(forLoop.loopVar!=null) {
|
||||
val varName = forLoop.loopVar.nameInSource.last()
|
||||
if(forLoop.decltype!=null) {
|
||||
val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(forLoop.loopVar.nameInSource, forLoop.body.statements.first())
|
||||
if(existing==null) {
|
||||
// create the local scoped for loop variable itself
|
||||
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, varName, null, null,
|
||||
isArray = false, autogeneratedDontRemove = true, position = forLoop.loopVar.position)
|
||||
vardecl.linkParents(forLoop.body)
|
||||
forLoop.body.statements.add(0, vardecl)
|
||||
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
|
||||
} else {
|
||||
val loopVar = forLoop.loopVar
|
||||
if (loopVar != null) {
|
||||
val varName = loopVar.nameInSource.last()
|
||||
if (forLoop.decltype != null) {
|
||||
val existing = if (forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(loopVar.nameInSource, forLoop.body.statements.first())
|
||||
if (existing == null) {
|
||||
// create the local scoped for loop variable itself
|
||||
val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, forLoop.zeropage, null, varName, null, null,
|
||||
isArray = false, autogeneratedDontRemove = true, position = loopVar.position)
|
||||
vardecl.linkParents(forLoop.body)
|
||||
forLoop.body.statements.add(0, vardecl)
|
||||
loopVar.parent = forLoop.body // loopvar 'is defined in the body'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(forLoop.iterable !is RangeExpr) {
|
||||
val existing = if(forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first())
|
||||
if(existing==null) {
|
||||
// create loop iteration counter variable (without value, to avoid an assignment)
|
||||
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, null, ForLoop.iteratorLoopcounterVarname, null, null,
|
||||
isArray = false, autogeneratedDontRemove = true, position = forLoop.loopVar.position)
|
||||
vardecl.linkParents(forLoop.body)
|
||||
forLoop.body.statements.add(0, vardecl)
|
||||
forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body'
|
||||
if (forLoop.iterable !is RangeExpr) {
|
||||
val existing = if (forLoop.body.containsNoCodeNorVars()) null else forLoop.body.lookup(listOf(ForLoop.iteratorLoopcounterVarname), forLoop.body.statements.first())
|
||||
if (existing == null) {
|
||||
// create loop iteration counter variable (without value, to avoid an assignment)
|
||||
val vardecl = VarDecl(VarDeclType.VAR, DataType.UBYTE, ZeropageWish.PREFER_ZEROPAGE, null, ForLoop.iteratorLoopcounterVarname, null, null,
|
||||
isArray = false, autogeneratedDontRemove = true, position = loopVar.position)
|
||||
vardecl.linkParents(forLoop.body)
|
||||
forLoop.body.statements.add(0, vardecl)
|
||||
loopVar.parent = forLoop.body // loopvar 'is defined in the body'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -233,8 +235,9 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
// a referencetype literal value that's not declared as a variable
|
||||
// we need to introduce an auto-generated variable for this to be able to refer to the value
|
||||
refLiteral.addToHeap(program.heap)
|
||||
val variable = VarDecl.createAuto(refLiteral, program.heap)
|
||||
addVarDecl(refLiteral.definingScope(), variable)
|
||||
val scope = refLiteral.definingScope()
|
||||
var variable = VarDecl.createAuto(refLiteral, program.heap)
|
||||
variable = addVarDecl(scope, variable)
|
||||
// replace the reference literal by a identifier reference
|
||||
val identifier = IdentifierReference(listOf(variable.name), variable.position)
|
||||
identifier.parent = refLiteral.parent
|
||||
@ -290,12 +293,17 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
||||
return expr
|
||||
}
|
||||
|
||||
private fun addVarDecl(scope: INameScope, variable: VarDecl) {
|
||||
private fun addVarDecl(scope: INameScope, variable: VarDecl): VarDecl {
|
||||
if(scope !in vardeclsToAdd)
|
||||
vardeclsToAdd[scope] = mutableListOf()
|
||||
val declList = vardeclsToAdd.getValue(scope)
|
||||
if(declList.all{it.name!=variable.name})
|
||||
val existing = declList.singleOrNull { it.name==variable.name }
|
||||
return if(existing!=null) {
|
||||
existing
|
||||
} else {
|
||||
declList.add(variable)
|
||||
variable
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package prog8.ast.processing
|
||||
|
||||
import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.*
|
||||
import prog8.ast.statements.*
|
||||
|
||||
@ -36,7 +37,7 @@ interface IAstModifyingVisitor {
|
||||
|
||||
fun visit(decl: VarDecl): Statement {
|
||||
decl.value = decl.value?.accept(this)
|
||||
decl.arraysize?.accept(this)
|
||||
decl.arraysize = decl.arraysize?.accept(this)
|
||||
return decl
|
||||
}
|
||||
|
||||
@ -49,6 +50,8 @@ interface IAstModifyingVisitor {
|
||||
val newtarget = functionCall.target.accept(this)
|
||||
if(newtarget is IdentifierReference)
|
||||
functionCall.target = newtarget
|
||||
else
|
||||
throw FatalAstException("cannot change class of function call target")
|
||||
functionCall.arglist = functionCall.arglist.map { it.accept(this) }.toMutableList()
|
||||
return functionCall
|
||||
}
|
||||
@ -57,6 +60,8 @@ interface IAstModifyingVisitor {
|
||||
val newtarget = functionCallStatement.target.accept(this)
|
||||
if(newtarget is IdentifierReference)
|
||||
functionCallStatement.target = newtarget
|
||||
else
|
||||
throw FatalAstException("cannot change class of function call target")
|
||||
functionCallStatement.arglist = functionCallStatement.arglist.map { it.accept(this) }.toMutableList()
|
||||
return functionCallStatement
|
||||
}
|
||||
@ -135,7 +140,12 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(forLoop: ForLoop): Statement {
|
||||
forLoop.loopVar?.accept(this)
|
||||
val newloopvar = forLoop.loopVar?.accept(this)
|
||||
when(newloopvar) {
|
||||
is IdentifierReference -> forLoop.loopVar = newloopvar
|
||||
null -> forLoop.loopVar = null
|
||||
else -> throw FatalAstException("can't change class of loopvar")
|
||||
}
|
||||
forLoop.iterable = forLoop.iterable.accept(this)
|
||||
forLoop.body = forLoop.body.accept(this) as AnonymousScope
|
||||
return forLoop
|
||||
@ -158,15 +168,24 @@ interface IAstModifyingVisitor {
|
||||
return returnStmt
|
||||
}
|
||||
|
||||
fun visit(arrayIndexedExpression: ArrayIndexedExpression): Expression {
|
||||
arrayIndexedExpression.identifier.accept(this)
|
||||
fun visit(arrayIndexedExpression: ArrayIndexedExpression): ArrayIndexedExpression {
|
||||
val ident = arrayIndexedExpression.identifier.accept(this)
|
||||
if(ident is IdentifierReference)
|
||||
arrayIndexedExpression.identifier = ident
|
||||
else
|
||||
throw FatalAstException("can't change class of indexed identifier")
|
||||
arrayIndexedExpression.arrayspec.accept(this)
|
||||
return arrayIndexedExpression
|
||||
}
|
||||
|
||||
fun visit(assignTarget: AssignTarget): AssignTarget {
|
||||
assignTarget.arrayindexed?.accept(this)
|
||||
assignTarget.identifier?.accept(this)
|
||||
val ident = assignTarget.identifier?.accept(this)
|
||||
when (ident) {
|
||||
is IdentifierReference -> assignTarget.identifier = ident
|
||||
null -> assignTarget.identifier = null
|
||||
else -> throw FatalAstException("can't change class of assign target identifier")
|
||||
}
|
||||
assignTarget.arrayindexed = assignTarget.arrayindexed?.accept(this)
|
||||
assignTarget.memoryAddress?.let { visit(it) }
|
||||
return assignTarget
|
||||
}
|
||||
@ -191,7 +210,11 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(addressOf: AddressOf): Expression {
|
||||
addressOf.identifier.accept(this)
|
||||
val ident = addressOf.identifier.accept(this)
|
||||
if(ident is IdentifierReference)
|
||||
addressOf.identifier = ident
|
||||
else
|
||||
throw FatalAstException("can't change class of addressof identifier")
|
||||
return addressOf
|
||||
}
|
||||
|
||||
@ -212,14 +235,19 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(whenStatement: WhenStatement): Statement {
|
||||
whenStatement.condition.accept(this)
|
||||
whenStatement.condition = whenStatement.condition.accept(this)
|
||||
whenStatement.choices.forEach { it.accept(this) }
|
||||
return whenStatement
|
||||
}
|
||||
|
||||
fun visit(whenChoice: WhenChoice) {
|
||||
whenChoice.values?.forEach { it.accept(this) }
|
||||
whenChoice.statements.accept(this)
|
||||
val stmt = whenChoice.statements.accept(this)
|
||||
if(stmt is AnonymousScope)
|
||||
whenChoice.statements = stmt
|
||||
else {
|
||||
whenChoice.statements = AnonymousScope(mutableListOf(stmt), stmt.position)
|
||||
}
|
||||
}
|
||||
|
||||
fun visit(structDecl: StructDecl): Statement {
|
||||
|
@ -198,7 +198,6 @@ class VarDecl(val type: VarDeclType,
|
||||
throw FatalAstException("can only create autovar for a ref lv that has a heapid $refLv")
|
||||
|
||||
val autoVarName = "$autoHeapValuePrefix${refLv.heapId}"
|
||||
|
||||
return if(refLv.isArray) {
|
||||
val declaredType = ArrayElementTypes.getValue(refLv.type)
|
||||
val arraysize = ArrayIndex.forArray(refLv, heap)
|
||||
@ -281,6 +280,12 @@ class VarDecl(val type: VarDeclType,
|
||||
structHasBeenFlattened = true
|
||||
return result
|
||||
}
|
||||
|
||||
fun withPrefixedName(nameprefix: String): Statement {
|
||||
val new = VarDecl(type, declaredDatatype, zeropage, arraysize, nameprefix+name, structName, value, isArray, autogeneratedDontRemove, position)
|
||||
new.parent = parent
|
||||
return new
|
||||
}
|
||||
}
|
||||
|
||||
class ArrayIndex(var index: Expression, override val position: Position) : Node {
|
||||
@ -298,9 +303,11 @@ class ArrayIndex(var index: Expression, override val position: Position) : Node
|
||||
}
|
||||
}
|
||||
|
||||
fun accept(visitor: IAstModifyingVisitor) {
|
||||
fun accept(visitor: IAstModifyingVisitor): ArrayIndex {
|
||||
index = index.accept(visitor)
|
||||
return this
|
||||
}
|
||||
|
||||
fun accept(visitor: IAstVisitor) {
|
||||
index.accept(visitor)
|
||||
}
|
||||
@ -337,9 +344,9 @@ class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, va
|
||||
: Assignment(target, aug_op, value, position)
|
||||
|
||||
data class AssignTarget(val register: Register?,
|
||||
val identifier: IdentifierReference?,
|
||||
val arrayindexed: ArrayIndexedExpression?,
|
||||
var memoryAddress: DirectMemoryWrite?,
|
||||
var identifier: IdentifierReference?,
|
||||
var arrayindexed: ArrayIndexedExpression?,
|
||||
val memoryAddress: DirectMemoryWrite?,
|
||||
override val position: Position) : Node {
|
||||
override lateinit var parent: Node
|
||||
|
||||
@ -370,12 +377,12 @@ data class AssignTarget(val register: Register?,
|
||||
return DataType.UBYTE
|
||||
|
||||
if(identifier!=null) {
|
||||
val symbol = program.namespace.lookup(identifier.nameInSource, stmt) ?: return null
|
||||
val symbol = program.namespace.lookup(identifier!!.nameInSource, stmt) ?: return null
|
||||
if (symbol is VarDecl) return symbol.datatype
|
||||
}
|
||||
|
||||
if(arrayindexed!=null) {
|
||||
val dt = arrayindexed.inferType(program)
|
||||
val dt = arrayindexed!!.inferType(program)
|
||||
if(dt!=null)
|
||||
return dt
|
||||
}
|
||||
@ -390,12 +397,12 @@ data class AssignTarget(val register: Register?,
|
||||
return when {
|
||||
this.memoryAddress!=null -> false
|
||||
this.register!=null -> value is RegisterExpr && value.register==register
|
||||
this.identifier!=null -> value is IdentifierReference && value.nameInSource==identifier.nameInSource
|
||||
this.identifier!=null -> value is IdentifierReference && value.nameInSource==identifier!!.nameInSource
|
||||
this.arrayindexed!=null -> value is ArrayIndexedExpression &&
|
||||
value.identifier.nameInSource==arrayindexed.identifier.nameInSource &&
|
||||
value.identifier.nameInSource==arrayindexed!!.identifier.nameInSource &&
|
||||
value.arrayspec.size()!=null &&
|
||||
arrayindexed.arrayspec.size()!=null &&
|
||||
value.arrayspec.size()==arrayindexed.arrayspec.size()
|
||||
arrayindexed!!.arrayspec.size()!=null &&
|
||||
value.arrayspec.size()==arrayindexed!!.arrayspec.size()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@ -406,16 +413,16 @@ data class AssignTarget(val register: Register?,
|
||||
if(this.register!=null && other.register!=null)
|
||||
return this.register==other.register
|
||||
if(this.identifier!=null && other.identifier!=null)
|
||||
return this.identifier.nameInSource==other.identifier.nameInSource
|
||||
return this.identifier!!.nameInSource==other.identifier!!.nameInSource
|
||||
if(this.memoryAddress!=null && other.memoryAddress!=null) {
|
||||
val addr1 = this.memoryAddress!!.addressExpression.constValue(program)
|
||||
val addr2 = other.memoryAddress!!.addressExpression.constValue(program)
|
||||
val addr1 = this.memoryAddress.addressExpression.constValue(program)
|
||||
val addr2 = other.memoryAddress.addressExpression.constValue(program)
|
||||
return addr1!=null && addr2!=null && addr1==addr2
|
||||
}
|
||||
if(this.arrayindexed!=null && other.arrayindexed!=null) {
|
||||
if(this.arrayindexed.identifier.nameInSource == other.arrayindexed.identifier.nameInSource) {
|
||||
val x1 = this.arrayindexed.arrayspec.index.constValue(program)
|
||||
val x2 = other.arrayindexed.arrayspec.index.constValue(program)
|
||||
if(this.arrayindexed!!.identifier.nameInSource == other.arrayindexed!!.identifier.nameInSource) {
|
||||
val x1 = this.arrayindexed!!.arrayspec.index.constValue(program)
|
||||
val x2 = other.arrayindexed!!.arrayspec.index.constValue(program)
|
||||
return x1!=null && x2!=null && x1==x2
|
||||
}
|
||||
}
|
||||
@ -428,12 +435,12 @@ data class AssignTarget(val register: Register?,
|
||||
if(this.memoryAddress!=null)
|
||||
return false
|
||||
if(this.arrayindexed!=null) {
|
||||
val targetStmt = this.arrayindexed.identifier.targetVarDecl(namespace)
|
||||
val targetStmt = this.arrayindexed!!.identifier.targetVarDecl(namespace)
|
||||
if(targetStmt!=null)
|
||||
return targetStmt.type!= VarDeclType.MEMORY
|
||||
}
|
||||
if(this.identifier!=null) {
|
||||
val targetStmt = this.identifier.targetVarDecl(namespace)
|
||||
val targetStmt = this.identifier!!.targetVarDecl(namespace)
|
||||
if(targetStmt!=null)
|
||||
return targetStmt.type!= VarDeclType.MEMORY
|
||||
}
|
||||
@ -684,7 +691,7 @@ class BranchStatement(var condition: BranchCondition,
|
||||
class ForLoop(val loopRegister: Register?,
|
||||
val decltype: DataType?,
|
||||
val zeropage: ZeropageWish,
|
||||
val loopVar: IdentifierReference?,
|
||||
var loopVar: IdentifierReference?,
|
||||
var iterable: Expression,
|
||||
var body: AnonymousScope,
|
||||
override val position: Position) : Statement() {
|
||||
@ -742,7 +749,7 @@ class RepeatLoop(var body: AnonymousScope,
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
}
|
||||
|
||||
class WhenStatement(val condition: Expression,
|
||||
class WhenStatement(var condition: Expression,
|
||||
val choices: MutableList<WhenChoice>,
|
||||
override val position: Position): Statement() {
|
||||
override lateinit var parent: Node
|
||||
@ -776,7 +783,7 @@ class WhenStatement(val condition: Expression,
|
||||
}
|
||||
|
||||
class WhenChoice(val values: List<Expression>?, // if null, this is the 'else' part
|
||||
val statements: AnonymousScope,
|
||||
var statements: AnonymousScope,
|
||||
override val position: Position) : Node {
|
||||
override lateinit var parent: Node
|
||||
|
||||
|
@ -5,7 +5,7 @@ import prog8.ast.Program
|
||||
import prog8.ast.base.*
|
||||
import prog8.ast.statements.Directive
|
||||
import prog8.compiler.target.c64.MachineDefinition
|
||||
import prog8.compiler.target.c64.codegen2.AnonymousScopeCleanup
|
||||
import prog8.compiler.target.c64.codegen2.AnonymousScopeVarsCleanup
|
||||
import prog8.compiler.target.c64.codegen2.AsmGen2
|
||||
import prog8.optimizer.constantFold
|
||||
import prog8.optimizer.optimizeStatements
|
||||
@ -92,7 +92,7 @@ fun compileProgram(filepath: Path,
|
||||
if(writeAssembly) {
|
||||
// asm generation directly from the Ast, no need for intermediate code
|
||||
val zeropage = MachineDefinition.C64Zeropage(compilerOptions)
|
||||
AnonymousScopeCleanup.moveVarsFromAnonymousScopesToSubroutines(programAst)
|
||||
AnonymousScopeVarsCleanup.moveVarsToSubroutine(programAst)
|
||||
val assembly = AsmGen2(programAst, compilerOptions, zeropage).compileToAssembly(optimize)
|
||||
assembly.assemble(compilerOptions)
|
||||
programName = assembly.name
|
||||
|
@ -1,31 +0,0 @@
|
||||
package prog8.compiler.target.c64.codegen2
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.processing.IAstVisitor
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
class AnonymousScopeCleanup(val program: Program): IAstVisitor {
|
||||
companion object {
|
||||
fun moveVarsFromAnonymousScopesToSubroutines(programAst: Program) {
|
||||
val cleanup = AnonymousScopeCleanup(programAst)
|
||||
cleanup.visit(programAst)
|
||||
|
||||
for((scope, decls) in cleanup.varsToMove) {
|
||||
decls.forEach { scope.remove(it) }
|
||||
val sub = scope.definingSubroutine()!!
|
||||
sub.statements.addAll(0, decls)
|
||||
decls.forEach { it.parent=sub }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val varsToMove: MutableMap<AnonymousScope, List<VarDecl>> = mutableMapOf()
|
||||
|
||||
override fun visit(scope: AnonymousScope) {
|
||||
val vardecls = scope.statements.filterIsInstance<VarDecl>()
|
||||
varsToMove[scope] = vardecls
|
||||
super.visit(scope)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package prog8.compiler.target.c64.codegen2
|
||||
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.base.FatalAstException
|
||||
import prog8.ast.expressions.Expression
|
||||
import prog8.ast.expressions.IdentifierReference
|
||||
import prog8.ast.processing.IAstModifyingVisitor
|
||||
import prog8.ast.statements.AnonymousScope
|
||||
import prog8.ast.statements.Statement
|
||||
import prog8.ast.statements.VarDecl
|
||||
|
||||
class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor {
|
||||
companion object {
|
||||
fun moveVarsToSubroutine(programAst: Program) {
|
||||
val cleanup = AnonymousScopeVarsCleanup(programAst)
|
||||
cleanup.visit(programAst)
|
||||
|
||||
for((scope, decls) in cleanup.varsToMove) {
|
||||
decls.forEach { scope.remove(it) }
|
||||
val sub = scope.definingSubroutine()!!
|
||||
val existingVariables = sub.statements.filterIsInstance<VarDecl>().map { it.name }.toSet()
|
||||
sub.statements.addAll(0, decls)
|
||||
decls.forEach {
|
||||
it.parent=sub
|
||||
if(it.name in existingVariables) {
|
||||
throw FatalAstException("variable ${it.name} already exists in ${sub.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val varsToMove: MutableMap<AnonymousScope, List<VarDecl>> = mutableMapOf()
|
||||
|
||||
override fun visit(scope: AnonymousScope): Statement {
|
||||
val scope2 = super.visit(scope) as AnonymousScope
|
||||
val vardecls = scope2.statements.filterIsInstance<VarDecl>()
|
||||
varsToMove[scope2] = vardecls
|
||||
return scope2
|
||||
}
|
||||
|
||||
private fun nameprefix(scope: AnonymousScope) = scope.name.replace("<", "").replace(">", "").replace("-", "") + "_"
|
||||
|
||||
override fun visit(decl: VarDecl): Statement {
|
||||
val decl2 = super.visit(decl) as VarDecl
|
||||
val scope = decl2.definingScope()
|
||||
if(scope is AnonymousScope) {
|
||||
return decl2.withPrefixedName(nameprefix(scope))
|
||||
}
|
||||
return decl2
|
||||
}
|
||||
|
||||
override fun visit(identifier: IdentifierReference): Expression {
|
||||
val ident = super.visit(identifier)
|
||||
if(ident !is IdentifierReference)
|
||||
return ident
|
||||
|
||||
val scope = ident.definingScope() as? AnonymousScope ?: return ident
|
||||
val vardecl = ident.targetVarDecl(program.namespace)
|
||||
return if(vardecl!=null) {
|
||||
// prefix the variable name reference
|
||||
ident.withPrefixedName(nameprefix(scope))
|
||||
} else {
|
||||
ident
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -548,7 +548,7 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun translateSubroutineCall(stmt: IFunctionCall) {
|
||||
val sub = stmt.target.targetSubroutine(program.namespace)!!
|
||||
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
if(Register.X in sub.asmClobbers)
|
||||
out(" stx c64.SCRATCH_ZPREGX") // we only save X for now (required! is the eval stack pointer), screw A and Y...
|
||||
|
||||
@ -1189,15 +1189,16 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignEvalResult(target: AssignTarget) {
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.register!=null -> {
|
||||
if(target.register==Register.X)
|
||||
throw AssemblyError("can't pop into X register - use variable instead")
|
||||
out(" inx | ld${target.register.name.toLowerCase()} $ESTACK_LO_HEX,x ")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
val targetDt = target.identifier.inferType(program)!!
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
val targetDt = targetIdent.inferType(program)!!
|
||||
when(targetDt) {
|
||||
DataType.UBYTE, DataType.BYTE -> {
|
||||
out(" inx | lda $ESTACK_LO_HEX,x | sta $targetName")
|
||||
@ -1222,7 +1223,7 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
}
|
||||
target.memoryAddress!=null -> {
|
||||
val address = target.memoryAddress!!.addressExpression
|
||||
val address = target.memoryAddress.addressExpression
|
||||
if(address is NumericLiteralValue) {
|
||||
out(" inx | lda $ESTACK_LO_HEX,x | sta ${address.number.toHex()}")
|
||||
} else {
|
||||
@ -1237,9 +1238,10 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignAddressOf(target: AssignTarget, name: IdentifierReference, scopedname: String) {
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
val struct = name.memberOfStruct(program.namespace)
|
||||
if(struct!=null) {
|
||||
// take the address of the first struct member instead
|
||||
@ -1271,9 +1273,10 @@ internal class AsmGen2(val program: Program,
|
||||
|
||||
private fun assignWordVariable(target: AssignTarget, variable: IdentifierReference) {
|
||||
val sourceName = asmIdentifierName(variable)
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda $sourceName
|
||||
ldy $sourceName+1
|
||||
@ -1287,9 +1290,10 @@ internal class AsmGen2(val program: Program,
|
||||
|
||||
private fun assignFloatVariable(target: AssignTarget, variable: IdentifierReference) {
|
||||
val sourceName = asmIdentifierName(variable)
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda $sourceName
|
||||
sta $targetName
|
||||
@ -1309,12 +1313,13 @@ internal class AsmGen2(val program: Program,
|
||||
|
||||
private fun assignByteVariable(target: AssignTarget, variable: IdentifierReference) {
|
||||
val sourceName = asmIdentifierName(variable)
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.register!=null -> {
|
||||
out(" ld${target.register.name.toLowerCase()} $sourceName")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda $sourceName
|
||||
sta $targetName
|
||||
@ -1325,9 +1330,11 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignRegister(target: AssignTarget, register: Register) {
|
||||
val targetIdent = target.identifier
|
||||
val targetArrayIdx = target.arrayindexed
|
||||
when {
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out(" st${register.name.toLowerCase()} $targetName")
|
||||
}
|
||||
target.register!=null -> {
|
||||
@ -1370,8 +1377,9 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignWordConstant(target: AssignTarget, word: Int) {
|
||||
if(target.identifier!=null) {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
val targetIdent = target.identifier
|
||||
if(targetIdent!=null) {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
if(word ushr 8 == word and 255) {
|
||||
// lsb=msb
|
||||
out("""
|
||||
@ -1393,12 +1401,13 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignByteConstant(target: AssignTarget, byte: Short) {
|
||||
val targetIdent = target.identifier
|
||||
when {
|
||||
target.register!=null -> {
|
||||
out(" ld${target.register.name.toLowerCase()} #${byte.toHex()}")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out(" lda #${byte.toHex()} | sta $targetName ")
|
||||
}
|
||||
else -> TODO("assign byte $byte to $target")
|
||||
@ -1406,10 +1415,11 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignFloatConstant(target: AssignTarget, float: Double) {
|
||||
val targetIdent = target.identifier
|
||||
if(float==0.0) {
|
||||
// optimized case for float zero
|
||||
if (target.identifier != null) {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
if (targetIdent != null) {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda #0
|
||||
sta $targetName
|
||||
@ -1424,8 +1434,8 @@ internal class AsmGen2(val program: Program,
|
||||
} else {
|
||||
// non-zero value
|
||||
val constFloat = getFloatConst(float)
|
||||
if (target.identifier != null) {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
if (targetIdent != null) {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda $constFloat
|
||||
sta $targetName
|
||||
@ -1445,13 +1455,14 @@ internal class AsmGen2(val program: Program,
|
||||
}
|
||||
|
||||
private fun assignMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) {
|
||||
val targetIdent = target.identifier
|
||||
if(address!=null) {
|
||||
when {
|
||||
target.register!=null -> {
|
||||
out(" ld${target.register.name.toLowerCase()} ${address.toHex()}")
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
lda ${address.toHex()}
|
||||
sta $targetName
|
||||
@ -1474,8 +1485,8 @@ internal class AsmGen2(val program: Program,
|
||||
Register.Y -> out(" tay")
|
||||
}
|
||||
}
|
||||
target.identifier!=null -> {
|
||||
val targetName = asmIdentifierName(target.identifier)
|
||||
targetIdent!=null -> {
|
||||
val targetName = asmIdentifierName(targetIdent)
|
||||
out("""
|
||||
ldy #0
|
||||
lda ($sourceName),y
|
||||
|
@ -472,7 +472,7 @@ class AstVm(val program: Program) {
|
||||
loopvar = IdentifierReference(listOf(stmt.loopRegister.name), stmt.position)
|
||||
} else {
|
||||
loopvarDt = stmt.loopVar!!.inferType(program)!!
|
||||
loopvar = stmt.loopVar
|
||||
loopvar = stmt.loopVar!!
|
||||
}
|
||||
val iterator = iterable.iterator()
|
||||
for (loopvalue in iterator) {
|
||||
@ -545,10 +545,12 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
|
||||
fun performAssignment(target: AssignTarget, value: RuntimeValue, contextStmt: Statement, evalCtx: EvalContext) {
|
||||
val targetIdent = target.identifier
|
||||
val targetArrayIndexed = target.arrayindexed
|
||||
when {
|
||||
target.identifier != null -> {
|
||||
val decl = contextStmt.definingScope().lookup(target.identifier.nameInSource, contextStmt) as? VarDecl
|
||||
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
|
||||
targetIdent != null -> {
|
||||
val decl = contextStmt.definingScope().lookup(targetIdent.nameInSource, contextStmt) as? VarDecl
|
||||
?: throw VmExecutionException("can't find assignment target $targetIdent")
|
||||
if (decl.type == VarDeclType.MEMORY) {
|
||||
val address = runtimeVariables.getMemoryAddress(decl.definingScope(), decl.name)
|
||||
when (decl.datatype) {
|
||||
@ -565,14 +567,14 @@ class AstVm(val program: Program) {
|
||||
runtimeVariables.set(decl.definingScope(), decl.name, value)
|
||||
}
|
||||
target.memoryAddress != null -> {
|
||||
val address = evaluate(target.memoryAddress!!.addressExpression, evalCtx).wordval!!
|
||||
val address = evaluate(target.memoryAddress.addressExpression, evalCtx).wordval!!
|
||||
evalCtx.mem.setUByte(address, value.byteval!!)
|
||||
}
|
||||
target.arrayindexed != null -> {
|
||||
val vardecl = target.arrayindexed.identifier.targetVarDecl(program.namespace)!!
|
||||
targetArrayIndexed != null -> {
|
||||
val vardecl = targetArrayIndexed.identifier.targetVarDecl(program.namespace)!!
|
||||
if(vardecl.type==VarDeclType.VAR) {
|
||||
val array = evaluate(target.arrayindexed.identifier, evalCtx)
|
||||
val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx)
|
||||
val array = evaluate(targetArrayIndexed.identifier, evalCtx)
|
||||
val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx)
|
||||
when (array.type) {
|
||||
DataType.ARRAY_UB -> {
|
||||
if (value.type != DataType.UBYTE)
|
||||
@ -606,7 +608,7 @@ class AstVm(val program: Program) {
|
||||
val indexInt = index.integerValue()
|
||||
val newchr = Petscii.decodePetscii(listOf(value.numericValue().toShort()), true)
|
||||
val newstr = array.str!!.replaceRange(indexInt, indexInt + 1, newchr)
|
||||
val ident = contextStmt.definingScope().lookup(target.arrayindexed.identifier.nameInSource, contextStmt) as? VarDecl
|
||||
val ident = contextStmt.definingScope().lookup(targetArrayIndexed.identifier.nameInSource, contextStmt) as? VarDecl
|
||||
?: throw VmExecutionException("can't find assignment target ${target.identifier}")
|
||||
val identScope = ident.definingScope()
|
||||
program.heap.update(array.heapId!!, newstr)
|
||||
@ -615,8 +617,8 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
else {
|
||||
val address = (vardecl.value as NumericLiteralValue).number.toInt()
|
||||
val index = evaluate(target.arrayindexed.arrayspec.index, evalCtx).integerValue()
|
||||
val elementType = target.arrayindexed.inferType(program)!!
|
||||
val index = evaluate(targetArrayIndexed.arrayspec.index, evalCtx).integerValue()
|
||||
val elementType = targetArrayIndexed.inferType(program)!!
|
||||
when(elementType) {
|
||||
DataType.UBYTE -> mem.setUByte(address+index, value.byteval!!)
|
||||
DataType.BYTE -> mem.setSByte(address+index, value.byteval!!)
|
||||
@ -952,4 +954,3 @@ class AstVm(val program: Program) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,18 +6,37 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
float f1 = 1.1
|
||||
float f2 = 2.2
|
||||
;
|
||||
; float f1 = 1.1
|
||||
; float f2 = 2.2
|
||||
;
|
||||
; @(1024) = f1==f2
|
||||
;
|
||||
; c64.CHROUT('\n')
|
||||
; c64scr.print_ub(f1==f2)
|
||||
; c64.CHROUT('\n')
|
||||
;
|
||||
; if f1 ==0.0
|
||||
; c64scr.print("error\n")
|
||||
; else
|
||||
; c64scr.print("ok\n")
|
||||
|
||||
@(1024) = f1==f2
|
||||
str s1 = "hello"
|
||||
str s2 = "hello"
|
||||
str s3 = "hello"
|
||||
str s4 = "hello"
|
||||
|
||||
c64.CHROUT('\n')
|
||||
c64scr.print_ub(f1==f2)
|
||||
c64.CHROUT('\n')
|
||||
if true {
|
||||
ubyte ub1 = 33
|
||||
A=ub1
|
||||
c64scr.print("irmen")
|
||||
}
|
||||
|
||||
if true {
|
||||
ubyte ub1 = 33
|
||||
A=ub1
|
||||
c64scr.print("irmen")
|
||||
}
|
||||
|
||||
if f1 ==0.0
|
||||
c64scr.print("error\n")
|
||||
else
|
||||
c64scr.print("ok\n")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user