added GoSub node (internal use only later for calling subroutines)

This commit is contained in:
Irmen de Jong 2021-11-21 16:23:48 +01:00
parent e86246a985
commit 8095c4c155
6 changed files with 64 additions and 81 deletions

View File

@ -1298,6 +1298,8 @@ $repeatLabel lda $counterVar
val jump = stmt.truepart.statements.first() as? Jump val jump = stmt.truepart.statements.first() as? Jump
if(jump!=null) { if(jump!=null) {
if(jump.isGosub)
throw FatalAstException("didn't expect GoSub here")
// branch with only a jump (goto) // branch with only a jump (goto)
val instruction = branchInstruction(stmt.condition, false) val instruction = branchInstruction(stmt.condition, false)
out(" $instruction ${getJumpTarget(jump)}") out(" $instruction ${getJumpTarget(jump)}")
@ -1387,7 +1389,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 { private fun getJumpTarget(jump: Jump): String {
val ident = jump.identifier val ident = jump.identifier

View File

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

View File

@ -169,6 +169,9 @@ internal class AstChecker(private val program: Program,
if(targetStatement is BuiltinFunctionStatementPlaceholder) if(targetStatement is BuiltinFunctionStatementPlaceholder)
errors.err("can't jump to a builtin function", jump.position) 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 val addr = jump.address
@ -224,7 +227,8 @@ internal class AstChecker(private val program: Program,
count++ count++
} }
override fun visit(jump: Jump) { override fun visit(jump: Jump) {
count++ if(!jump.isGosub)
count++
} }
} }

View File

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

View File

@ -92,10 +92,7 @@ class Block(override val name: String,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "Block(name=$name, address=$address, ${statements.size} statements)"
override fun toString(): String {
return "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() 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 copy() = Label(name, position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString()= "Label(name=$name, pos=$position)"
override fun toString(): String {
return "Label(name=$name, pos=$position)"
}
} }
open class Return(var value: Expression?, final override val position: Position) : Statement() { 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 copy() = Return(value?.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "Return($value, pos=$position)"
override fun toString(): String {
return "Return($value, pos=$position)"
}
} }
class Break(override val position: Position) : Statement() { class Break(override val position: Position) : Statement() {
@ -256,10 +247,8 @@ open class VarDecl(val type: VarDeclType,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() =
override fun toString(): String { "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
return "VarDecl(name=$name, vartype=$type, datatype=$datatype, value=$value, pos=$position)"
}
fun zeroElementValue(): NumericLiteralValue { fun zeroElementValue(): NumericLiteralValue {
if(allowInitializeWithZero) if(allowInitializeWithZero)
@ -303,10 +292,7 @@ class ArrayIndex(var indexExpr: Expression,
fun accept(visitor: IAstVisitor) = indexExpr.accept(visitor) fun accept(visitor: IAstVisitor) = indexExpr.accept(visitor)
fun accept(visitor: AstWalker) = indexExpr.accept(visitor, this) fun accept(visitor: AstWalker) = indexExpr.accept(visitor, this)
override fun toString() = "ArrayIndex($indexExpr, pos=$position)"
override fun toString(): String {
return("ArrayIndex($indexExpr, pos=$position)")
}
fun constIndex() = (indexExpr as? NumericLiteralValue)?.number?.toInt() fun constIndex() = (indexExpr as? NumericLiteralValue)?.number?.toInt()
@ -335,10 +321,7 @@ open class Assignment(var target: AssignTarget, var value: Expression, final ove
override fun copy()= Assignment(target.copy(), value.copy(), position) override fun copy()= Assignment(target.copy(), value.copy(), position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "Assignment(target: $target, value: $value, pos=$position)"
override fun toString(): String {
return("Assignment(target: $target, value: $value, pos=$position)")
}
/** /**
* Is the assigment value an expression that references the assignment target itself? * Is the assigment value an expression that references the assignment target itself?
@ -514,17 +497,15 @@ class PostIncrDecr(var target: AssignTarget, val operator: String, override val
override fun copy() = PostIncrDecr(target.copy(), operator, position) override fun copy() = PostIncrDecr(target.copy(), operator, position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "PostIncrDecr(op: $operator, target: $target, pos=$position)"
override fun toString(): String {
return "PostIncrDecr(op: $operator, target: $target, pos=$position)"
}
} }
class Jump(val address: UInt?, open class Jump(val address: UInt?,
val identifier: IdentifierReference?, val identifier: IdentifierReference?,
val generatedLabel: String?, // used in code generation scenarios val generatedLabel: String?, // can be used in code generation scenarios
override val position: Position) : Statement() { override val position: Position) : Statement() {
override lateinit var parent: Node override lateinit var parent: Node
open val isGosub = false
override fun linkParents(parent: Node) { override fun linkParents(parent: Node) {
this.parent = parent this.parent = parent
@ -536,9 +517,18 @@ class Jump(val address: UInt?,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString(): String { override fun toString() =
return "Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)" "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, class FunctionCallStatement(override var target: IdentifierReference,
@ -567,7 +557,6 @@ class FunctionCallStatement(override var target: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "FunctionCallStatement(target=$target, pos=$position)" override fun toString() = "FunctionCallStatement(target=$target, pos=$position)"
} }
@ -695,10 +684,8 @@ class Subroutine(override val name: String,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() =
override fun toString(): String { "Subroutine(name=$name, parameters=$parameters, returntypes=$returntypes, ${statements.size} statements, address=$asmAddress)"
return "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 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) } fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in arrayOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
@ -825,10 +812,7 @@ class ForLoop(var loopVar: IdentifierReference,
override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun toString() = "ForLoop(loopVar: $loopVar, iterable: $iterable, pos=$position)"
override fun toString(): String {
return "ForLoop(loopVar: $loopVar, iterable: $iterable, pos=$position)"
}
fun loopVarDt(program: Program) = loopVar.inferType(program) fun loopVarDt(program: Program) = loopVar.inferType(program)
} }
@ -978,9 +962,7 @@ class WhenChoice(var values: MutableList<Expression>?, // if null, th
} }
override fun copy() = WhenChoice(values?.map{ it.copy() }?.toMutableList(), statements.copy(), position) override fun copy() = WhenChoice(values?.map{ it.copy() }?.toMutableList(), statements.copy(), position)
override fun toString(): String { override fun toString() = "Choice($values at $position)"
return "Choice($values at $position)"
}
fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
@ -1000,10 +982,7 @@ class DirectMemoryWrite(var addressExpression: Expression, override val position
replacement.parent = this replacement.parent = this
} }
override fun toString(): String { override fun toString() = "DirectMemoryWrite($addressExpression)"
return "DirectMemoryWrite($addressExpression)"
}
fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: IAstVisitor) = visitor.visit(this)
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
override fun copy() = DirectMemoryWrite(addressExpression.copy(), position) override fun copy() = DirectMemoryWrite(addressExpression.copy(), position)

View File

@ -4,30 +4,19 @@ main {
sub start() { sub start() {
repeat 100 { ubyte xx = 20
random_rgb12() routine(xx)
txt.print_ubhex(target_red,false) xx++
txt.print_ubhex(target_green,false) routine(xx)
txt.print_ubhex(target_blue,false) xx++
txt.nl() routine(xx)
}
repeat { repeat {
} }
} }
ubyte target_red sub routine(ubyte x) {
ubyte target_green txt.print_ub(x)
ubyte target_blue txt.spc()
}
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
}
} }