Merge branch 'ref-subroutine-param' into v7.4-dev

# Conflicts:
#	compilerAst/src/prog8/ast/AstToplevel.kt
This commit is contained in:
Irmen de Jong 2021-11-26 01:12:14 +01:00
commit 17d403d812
16 changed files with 158 additions and 113 deletions

View File

@ -720,7 +720,6 @@ class AsmGen(private val program: Program,
internal fun translate(stmt: Statement) {
outputSourceLine(stmt)
when(stmt) {
is ParameterVarDecl -> { /* subroutine parameter vardecls don't get any special treatment here */ }
is VarDecl -> translate(stmt)
is NopStatement -> {}
is Directive -> translate(stmt)
@ -1298,6 +1297,8 @@ $repeatLabel lda $counterVar
val jump = stmt.truepart.statements.first() as? Jump
if(jump!=null) {
if(jump.isGosub)
throw FatalAstException("didn't expect GoSub here")
// branch with only a jump (goto)
val instruction = branchInstruction(stmt.condition, false)
out(" $instruction ${getJumpTarget(jump)}")
@ -1387,7 +1388,12 @@ $label nop""")
}
}
private fun translate(jump: Jump) = jmp(getJumpTarget(jump))
private fun translate(jump: Jump) {
if(jump.isGosub)
out(" jsr ${getJumpTarget(jump)}")
else
jmp(getJumpTarget(jump))
}
private fun getJumpTarget(jump: Jump): String {
val ident = jump.identifier

View File

@ -62,7 +62,13 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
throw AssemblyError("unknown dt")
val dt = idt.getOr(DataType.UNDEFINED)
when {
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
identifier != null -> {
val parameter = identifier!!.targetVarDecl(program)?.subroutineParameter
if(parameter!=null && parameter.definingSubroutine!!.isAsmSubroutine) {
TODO("ASSIGN ASMPARAM $parameter :: $assign")
}
AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
}
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this)
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this)
else -> throw AssemblyError("weird target")
@ -133,6 +139,10 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
is StringLiteralValue -> throw AssemblyError("string literal value should not occur anymore for asm generation")
is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation")
is IdentifierReference -> {
val parameter = value.targetVarDecl(program)?.subroutineParameter
if(parameter!=null && parameter.definingSubroutine!!.isAsmSubroutine) {
TODO("ASSIGN SOURCE FROM ASMPARAM $parameter :: $value")
}
val dt = value.inferType(program).getOr(DataType.UNDEFINED)
val varName=asmgen.asmVariableName(value)
// special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system

View File

@ -46,8 +46,8 @@ class AsmGenSymbolsTests: StringSpec({
}
*/
val varInSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteralValue.optimalInteger(1234, Position.DUMMY), false, false, false, Position.DUMMY)
val var2InSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, false, Position.DUMMY)
val varInSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "localvar", NumericLiteralValue.optimalInteger(1234, Position.DUMMY), false, false, false, null, Position.DUMMY)
val var2InSub = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", null, false, false, false, null, Position.DUMMY)
val labelInSub = Label("locallabel", Position.DUMMY)
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
@ -63,7 +63,7 @@ class AsmGenSymbolsTests: StringSpec({
val statements = mutableListOf(varInSub, var2InSub, labelInSub, assign1, assign2, assign3, assign4, assign5, assign6, assign7, assign8)
val subroutine = Subroutine("start", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, statements, Position.DUMMY)
val labelInBlock = Label("label_outside", Position.DUMMY)
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY)
val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, null, Position.DUMMY)
val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY)
val module = Module(mutableListOf(block), Position.DUMMY, SourceCode.Generated("test"))

View File

@ -277,12 +277,13 @@ class StatementOptimizer(private val program: Program,
}
override fun after(jump: Jump, parent: Node): Iterable<IAstModification> {
// if the jump is to the next statement, remove the jump
val scope = jump.parent as IStatementContainer
val label = jump.identifier?.targetStatement(program)
if(label!=null && scope.statements.indexOf(label) == scope.statements.indexOf(jump)+1)
return listOf(IAstModification.Remove(jump, scope))
if(!jump.isGosub) {
// if the jump is to the next statement, remove the jump
val scope = jump.parent as IStatementContainer
val label = jump.identifier?.targetStatement(program)
if (label != null && scope.statements.indexOf(label) == scope.statements.indexOf(jump) + 1)
return listOf(IAstModification.Remove(jump, scope))
}
return noModifications
}

View File

@ -83,14 +83,18 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
IAstModification.ReplaceNode(it, uwordParam, subroutine)
}
val stringParamNames = stringParams.map { it.name }.toSet()
val varsChanges = subroutine.statements
.filterIsInstance<VarDecl>()
.filter { it.autogeneratedDontRemove && it.name in stringParamNames }
.map {
val newvar = VarDecl(it.type, DataType.UWORD, it.zeropage, null, it.name, null, false, true, it.sharedWithAsm, it.position)
IAstModification.ReplaceNode(it, newvar, subroutine)
val stringParamsByNames = stringParams.associateBy { it.name }
val varsChanges =
if(stringParamsByNames.isNotEmpty()) {
subroutine.statements
.filterIsInstance<VarDecl>()
.filter { it.subroutineParameter!=null && it.name in stringParamsByNames }
.map {
val newvar = VarDecl(it.type, DataType.UWORD, it.zeropage, null, it.name, null, false, true, it.sharedWithAsm, stringParamsByNames.getValue(it.name), it.position)
IAstModification.ReplaceNode(it, newvar, subroutine)
}
}
else emptyList()
return parameterChanges + varsChanges
}

View File

@ -169,6 +169,9 @@ internal class AstChecker(private val program: Program,
if(targetStatement is BuiltinFunctionStatementPlaceholder)
errors.err("can't jump to a builtin function", jump.position)
}
if(!jump.isGosub && targetStatement is Subroutine && targetStatement.parameters.any()) {
errors.err("can't jump to a subroutine that takes parameters", jump.position)
}
}
val addr = jump.address
@ -224,7 +227,8 @@ internal class AstChecker(private val program: Program,
count++
}
override fun visit(jump: Jump) {
count++
if(!jump.isGosub)
count++
}
}

View File

@ -75,7 +75,7 @@ internal class AstIdentifiersChecker(private val errors: IErrorReporter, private
val paramsToCheck = paramNames.intersect(namesInSub)
for(name in paramsToCheck) {
val symbol = subroutine.searchSymbol(name)
if(symbol!=null && symbol.position != subroutine.position)
if(symbol!=null && (symbol as? VarDecl)?.subroutineParameter==null)
nameError(name, symbol.position, subroutine)
}

View File

@ -20,13 +20,13 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
val symbolsInSub = subroutine.allDefinedSymbols
val namesInSub = symbolsInSub.map{ it.first }.toSet()
if(subroutine.asmAddress==null) {
if(subroutine.asmParameterRegisters.isEmpty() && subroutine.parameters.isNotEmpty()) {
if(!subroutine.isAsmSubroutine && subroutine.parameters.isNotEmpty()) {
val vars = subroutine.statements.filterIsInstance<VarDecl>().map { it.name }.toSet()
if(!vars.containsAll(subroutine.parameters.map{it.name})) {
return subroutine.parameters
.filter { it.name !in namesInSub }
.map {
val vardecl = ParameterVarDecl(it.name, it.type, subroutine.position)
val vardecl = VarDecl.fromParameter(it)
IAstModification.InsertFirst(vardecl, subroutine)
}
}

View File

@ -110,7 +110,7 @@ class TestMemory: FunSpec({
}
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
val decl = VarDecl(vartype, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
val decl = VarDecl(vartype, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, null, Position.DUMMY)
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -149,7 +149,7 @@ class TestMemory: FunSpec({
}
test("regular variable not in mapped IO ram on C64") {
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", null, false, false, false, null, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -160,8 +160,8 @@ class TestMemory: FunSpec({
}
test("memory mapped variable not in mapped IO ram on C64") {
val address = 0x1000
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
val address = 0x1000u
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, null, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -172,8 +172,8 @@ class TestMemory: FunSpec({
}
test("memory mapped variable in mapped IO ram on C64") {
val address = 0xd020
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
val address = 0xd020u
val decl = VarDecl(VarDeclType.MEMORY, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, null, Position.DUMMY)
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", mutableListOf(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
@ -184,7 +184,7 @@ class TestMemory: FunSpec({
}
test("array not in mapped IO ram") {
val decl = VarDecl(VarDeclType.VAR, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, false, Position.DUMMY)
val decl = VarDecl(VarDeclType.VAR, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", null, false, false, false, null, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -196,8 +196,8 @@ class TestMemory: FunSpec({
}
test("memory mapped array not in mapped IO ram") {
val address = 0x1000
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
val address = 0x1000u
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, null, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
@ -209,8 +209,8 @@ class TestMemory: FunSpec({
}
test("memory mapped array in mapped IO ram") {
val address = 0xd800
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, Position.DUMMY)
val address = 0xd800u
val decl = VarDecl(VarDeclType.MEMORY, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", NumericLiteralValue.optimalInteger(address, Position.DUMMY), false, false, false, null, Position.DUMMY)
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteralValue.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)

View File

@ -219,7 +219,10 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
}
override fun visit(jump: Jump) {
output("goto ")
if(jump.isGosub)
output("gosub ")
else
output("goto ")
when {
jump.address!=null -> output(jump.address.toHex())
jump.generatedLabel!=null -> output(jump.generatedLabel)

View File

@ -68,6 +68,9 @@ interface IStatementContainer {
fun isNotEmpty(): Boolean = statements.isNotEmpty()
fun searchSymbol(name: String): Statement? {
if(this is Subroutine && isAsmSubroutine)
return searchAsmParameter(name)
// this is called quite a lot and could perhaps be optimized a bit more,
// but adding a memoization cache didn't make much of a practical runtime difference...
for (stmt in statements) {

View File

@ -94,7 +94,7 @@ class Program(val name: String,
val varName = "string_${internedStringsBlock.statements.size}"
val decl = VarDecl(
VarDeclType.VAR, DataType.STR, ZeropageWish.NOT_IN_ZEROPAGE, null, varName, string,
isArray = false, autogeneratedDontRemove = true, sharedWithAsm = false, position = string.position
isArray = false, autogeneratedDontRemove = true, sharedWithAsm = false, subroutineParameter = null, position = string.position
)
internedStringsBlock.statements.add(decl)
decl.linkParents(internedStringsBlock)

View File

@ -64,6 +64,7 @@ private fun Prog8ANTLRParser.VariabledeclarationContext.toAst() : Statement {
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
vd.SHARED()!=null,
null,
it.toPosition()
)
}
@ -81,6 +82,7 @@ private fun Prog8ANTLRParser.VariabledeclarationContext.toAst() : Statement {
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
vd.SHARED() != null,
null,
cvarinit.toPosition()
)
}
@ -98,6 +100,7 @@ private fun Prog8ANTLRParser.VariabledeclarationContext.toAst() : Statement {
vd.ARRAYSIG() != null || vd.arrayindex() != null,
false,
vd.SHARED()!=null,
null,
mvarinit.toPosition()
)
}
@ -600,6 +603,7 @@ private fun Prog8ANTLRParser.VardeclContext.toAst(): VarDecl {
ARRAYSIG() != null || arrayindex() != null,
false,
SHARED()!=null,
null,
toPosition()
)
}

View File

@ -92,10 +92,7 @@ class Block(override val name: String,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "Block(name=$name, address=$address, ${statements.size} statements)"
}
override fun toString() = "Block(name=$name, address=$address, ${statements.size} statements)"
fun options() = statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.map {it.name!!}.toSet()
}
@ -135,10 +132,7 @@ data class Label(override val name: String, override val position: Position) : S
override fun copy() = Label(name, position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "Label(name=$name, pos=$position)"
}
override fun toString()= "Label(name=$name, pos=$position)"
}
open class Return(var value: Expression?, final override val position: Position) : Statement() {
@ -158,10 +152,7 @@ open class Return(var value: Expression?, final override val position: Position)
override fun copy() = Return(value?.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "Return($value, pos=$position)"
}
override fun toString() = "Return($value, pos=$position)"
}
class Break(override val position: Position) : Statement() {
@ -194,6 +185,7 @@ open class VarDecl(val type: VarDeclType,
val isArray: Boolean,
val autogeneratedDontRemove: Boolean,
val sharedWithAsm: Boolean,
val subroutineParameter: SubroutineParameter?,
final override val position: Position) : Statement(), INamedStatement {
override lateinit var parent: Node
var allowInitializeWithZero = true
@ -203,6 +195,16 @@ open class VarDecl(val type: VarDeclType,
companion object {
private var autoHeapValueSequenceNumber = 0
fun fromParameter(param: SubroutineParameter): VarDecl {
return VarDecl(VarDeclType.VAR, param.type, ZeropageWish.DONTCARE, null, param.name, null,
isArray = false,
autogeneratedDontRemove = true,
sharedWithAsm = false,
subroutineParameter = param,
position = param.position
)
}
fun createAuto(array: ArrayLiteralValue): VarDecl {
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
val arrayDt =
@ -213,7 +215,7 @@ open class VarDecl(val type: VarDeclType,
val declaredType = ArrayToElementTypes.getValue(arrayDt)
val arraysize = ArrayIndex.forArray(array)
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, array,
isArray = true, autogeneratedDontRemove = true, sharedWithAsm = false, position = array.position)
isArray = true, autogeneratedDontRemove = true, sharedWithAsm = false, subroutineParameter = null, position = array.position)
}
fun defaultZero(dt: DataType, position: Position) = when(dt) {
@ -256,10 +258,8 @@ open class VarDecl(val type: VarDeclType,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
}
override fun toString() =
"VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
fun zeroElementValue(): NumericLiteralValue {
if(allowInitializeWithZero)
@ -269,16 +269,13 @@ open class VarDecl(val type: VarDeclType,
}
override fun copy(): VarDecl {
val c = VarDecl(type, declaredDatatype, zeropage, arraysize?.copy(), name, value?.copy(), isArray, autogeneratedDontRemove, sharedWithAsm, position)
val c = VarDecl(type, declaredDatatype, zeropage, arraysize?.copy(), name, value?.copy(),
isArray, autogeneratedDontRemove, sharedWithAsm, subroutineParameter, position)
c.allowInitializeWithZero = this.allowInitializeWithZero
return c
}
}
// a vardecl used only for subroutine parameters
class ParameterVarDecl(name: String, declaredDatatype: DataType, position: Position)
: VarDecl(VarDeclType.VAR, declaredDatatype, ZeropageWish.DONTCARE, null, name, null, false, true, false, position)
class ArrayIndex(var indexExpr: Expression,
override val position: Position) : Node {
override lateinit var parent: Node
@ -303,10 +300,7 @@ class ArrayIndex(var indexExpr: Expression,
fun accept(visitor: IAstVisitor) = indexExpr.accept(visitor)
fun accept(visitor: AstWalker) = indexExpr.accept(visitor, this)
override fun toString(): String {
return("ArrayIndex($indexExpr, pos=$position)")
}
override fun toString() = "ArrayIndex($indexExpr, pos=$position)"
fun constIndex() = (indexExpr as? NumericLiteralValue)?.number?.toInt()
@ -335,10 +329,7 @@ open class Assignment(var target: AssignTarget, var value: Expression, final ove
override fun copy()= Assignment(target.copy(), value.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return("Assignment(target: $target, value: $value, pos=$position)")
}
override fun toString() = "Assignment(target: $target, value: $value, pos=$position)"
/**
* Is the assigment value an expression that references the assignment target itself?
@ -514,17 +505,15 @@ class PostIncrDecr(var target: AssignTarget, val operator: String, override val
override fun copy() = PostIncrDecr(target.copy(), operator, position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "PostIncrDecr(op: $operator, target: $target, pos=$position)"
}
override fun toString() = "PostIncrDecr(op: $operator, target: $target, pos=$position)"
}
class Jump(val address: UInt?,
val identifier: IdentifierReference?,
val generatedLabel: String?, // used in code generation scenarios
override val position: Position) : Statement() {
open class Jump(val address: UInt?,
val identifier: IdentifierReference?,
val generatedLabel: String?, // can be used in code generation scenarios
override val position: Position) : Statement() {
override lateinit var parent: Node
open val isGosub = false
override fun linkParents(parent: Node) {
this.parent = parent
@ -536,9 +525,18 @@ class Jump(val address: UInt?,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
}
override fun toString() =
"Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
}
// a GoSub is ONLY created internally for calling subroutines
class GoSub(address: UInt?, identifier: IdentifierReference?, generatedLabel: String?, position: Position) :
Jump(address, identifier, generatedLabel, position) {
override val isGosub = true
override fun copy() = GoSub(address, identifier?.copy(), generatedLabel, position)
override fun toString() =
"GoSub(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
}
class FunctionCallStatement(override var target: IdentifierReference,
@ -567,7 +565,6 @@ class FunctionCallStatement(override var target: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "FunctionCallStatement(target=$target, pos=$position)"
}
@ -695,10 +692,8 @@ class Subroutine(override val name: String,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "Subroutine(name=$name, parameters=$parameters, returntypes=$returntypes, ${statements.size} statements, address=$asmAddress)"
}
override fun toString() =
"Subroutine(name=$name, parameters=$parameters, returntypes=$returntypes, ${statements.size} statements, address=$asmAddress)"
fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
@ -722,6 +717,24 @@ class Subroutine(override val name: String,
.filter { it is InlineAssembly }
.map { (it as InlineAssembly).assembly }
.count { " rti" in it || "\trti" in it || " rts" in it || "\trts" in it || " jmp" in it || "\tjmp" in it || " bra" in it || "\tbra" in it}
// code to provide the ability to reference asmsub parameters via qualified name:
private val asmParamsDecls = mutableMapOf<String, VarDecl>()
fun searchAsmParameter(name: String): VarDecl? {
require(isAsmSubroutine)
val existingDecl = asmParamsDecls[name]
if(existingDecl!=null)
return existingDecl
val param = parameters.firstOrNull {it.name==name} ?: return null
val decl = VarDecl.fromParameter(param)
decl.linkParents(this)
asmParamsDecls[name] = decl
return decl
}
}
open class SubroutineParameter(val name: String,
@ -825,10 +838,7 @@ class ForLoop(var loopVar: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String {
return "ForLoop(loopVar: $loopVar, iterable: $iterable, pos=$position)"
}
override fun toString() = "ForLoop(loopVar: $loopVar, iterable: $iterable, pos=$position)"
fun loopVarDt(program: Program) = loopVar.inferType(program)
}
@ -978,9 +988,7 @@ class WhenChoice(var values: MutableList<Expression>?, // if null, th
}
override fun copy() = WhenChoice(values?.map{ it.copy() }?.toMutableList(), statements.copy(), position)
override fun toString(): String {
return "Choice($values at $position)"
}
override fun toString() = "Choice($values at $position)"
fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
@ -1000,10 +1008,7 @@ class DirectMemoryWrite(var addressExpression: Expression, override val position
replacement.parent = this
}
override fun toString(): String {
return "DirectMemoryWrite($addressExpression)"
}
override fun toString() = "DirectMemoryWrite($addressExpression)"
fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun copy() = DirectMemoryWrite(addressExpression.copy(), position)

View File

@ -3,6 +3,12 @@ TODO
For next compiler release (7.4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Use GoSub to call subroutines (not in expressions?):
- [DONE] allow separate assigns to subroutine's parameter variables / registers
- for asmsubs: implement asmgen for assigning to asm parameter (register)
- for asmsubs: implement asmgen for reading asm parameter (register)
- replace subroutine param load code with just the right order of those assigns
- finally replace the actual call with a GoSub
...

View File

@ -1,33 +1,32 @@
%import textio
main {
sub start() {
ubyte @shared xx
main.routine.r1arg = 20
; main.routine2.r2arg = 20 ; TODO asmgen
repeat 100 {
random_rgb12()
txt.print_ubhex(target_red,false)
txt.print_ubhex(target_green,false)
txt.print_ubhex(target_blue,false)
txt.nl()
}
xx = main.routine.r1arg
xx++
;xx = main.routine2.r2arg ; TODO asmgen
;xx++
printstuff("hello")
repeat {
}
}
ubyte target_red
ubyte target_green
ubyte target_blue
sub printstuff(str addr) {
sub random_rgb12() {
do {
uword rr = rndw()
target_red = msb(rr) & 15
target_green = lsb(rr)
target_blue = target_green & 15
target_green >>= 4
} until target_red+target_green+target_blue >= 12
}
}
sub routine(ubyte r1arg) {
r1arg++
}
asmsub routine2(ubyte r2arg @ A) {
%asm {{
rts
}}
}
}