mirror of
https://github.com/irmen/prog8.git
synced 2026-04-21 17:16:33 +00:00
gosub only uses an identifier
This commit is contained in:
@@ -86,14 +86,9 @@ class PtForLoop(position: Position) : PtNode(position) {
|
||||
}
|
||||
|
||||
|
||||
class PtGosub(val identifier: PtIdentifier?,
|
||||
val address: UInt?,
|
||||
val generatedLabel: String?,
|
||||
position: Position) : PtNode(position) {
|
||||
class PtGosub(val identifier: PtIdentifier, position: Position) : PtNode(position) {
|
||||
override fun printProperties() {
|
||||
identifier?.printProperties()
|
||||
if(address!=null) print(address.toHex())
|
||||
if(generatedLabel!=null) print(generatedLabel)
|
||||
identifier.printProperties()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
private fun translate(gosub: GoSub) {
|
||||
val tgt = gosub.identifier!!.targetSubroutine(program)
|
||||
val tgt = gosub.identifier.targetSubroutine(program)
|
||||
if(tgt!=null && tgt.isAsmSubroutine) {
|
||||
// no need to rescue X , this has been taken care of already
|
||||
out(" jsr ${getJumpTarget(gosub)}")
|
||||
@@ -917,17 +917,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
private fun getJumpTarget(gosub: GoSub): String {
|
||||
val ident = gosub.identifier
|
||||
val label = gosub.generatedLabel
|
||||
val addr = gosub.address
|
||||
return when {
|
||||
ident!=null -> asmSymbolName(ident)
|
||||
label!=null -> label
|
||||
addr!=null -> addr.toHex()
|
||||
else -> "????"
|
||||
}
|
||||
}
|
||||
private fun getJumpTarget(gosub: GoSub): String = asmSymbolName(gosub.identifier)
|
||||
|
||||
private fun translate(ret: Return, withRts: Boolean=true) {
|
||||
ret.value?.let { returnvalue ->
|
||||
|
||||
@@ -36,7 +36,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
|
||||
internal fun saveXbeforeCall(gosub: GoSub) {
|
||||
val sub = gosub.identifier?.targetSubroutine(program)
|
||||
val sub = gosub.identifier.targetSubroutine(program)
|
||||
if(sub?.shouldSaveX()==true) {
|
||||
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||
if(regSaveOnStack)
|
||||
@@ -58,7 +58,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
}
|
||||
|
||||
internal fun restoreXafterCall(gosub: GoSub) {
|
||||
val sub = gosub.identifier?.targetSubroutine(program)
|
||||
val sub = gosub.identifier.targetSubroutine(program)
|
||||
if(sub?.shouldSaveX()==true) {
|
||||
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||
if(regSaveOnStack)
|
||||
|
||||
@@ -556,11 +556,7 @@ class AstToXmlConverter(internal val program: PtProgram,
|
||||
|
||||
private fun write(gosub: PtGosub) {
|
||||
xml.elt("gosub")
|
||||
if(gosub.identifier!=null) xml.attr("symbol", strTargetName(gosub.identifier!!))
|
||||
else if(gosub.address!=null) xml.attr("address", gosub.address!!.toString())
|
||||
else if(gosub.generatedLabel!=null) xml.attr("label", gosub.generatedLabel!!)
|
||||
else
|
||||
throw InternalCompilerException("weird jump target")
|
||||
xml.attr("symbol", strTargetName(gosub.identifier))
|
||||
xml.endElt()
|
||||
}
|
||||
|
||||
|
||||
@@ -135,13 +135,7 @@ class CodeGen(internal val program: PtProgram,
|
||||
|
||||
private fun translate(gosub: PtGosub): VmCodeChunk {
|
||||
val chunk = VmCodeChunk()
|
||||
if(gosub.address!=null)
|
||||
throw AssemblyError("cannot gosub to a memory address in the vm target")
|
||||
else if(gosub.identifier!=null) {
|
||||
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier!!.targetName))
|
||||
} else if(gosub.generatedLabel!=null) {
|
||||
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(listOf(gosub.generatedLabel!!)))
|
||||
}
|
||||
chunk += VmCodeOpcodeWithStringArg(Opcode.GOSUB, gosubArg(gosub.identifier.targetName))
|
||||
return chunk
|
||||
}
|
||||
|
||||
|
||||
@@ -291,13 +291,13 @@ class StatementOptimizer(private val program: Program,
|
||||
|
||||
override fun after(gosub: GoSub, parent: Node): Iterable<IAstModification> {
|
||||
// if the next statement is return with no returnvalue, change into a regular jump if there are no parameters as well.
|
||||
val subroutineParams = gosub.identifier?.targetSubroutine(program)?.parameters
|
||||
val subroutineParams = gosub.identifier.targetSubroutine(program)?.parameters
|
||||
if(subroutineParams!=null && subroutineParams.isEmpty()) {
|
||||
val returnstmt = gosub.nextSibling() as? Return
|
||||
if(returnstmt!=null && returnstmt.value==null) {
|
||||
return listOf(
|
||||
IAstModification.Remove(returnstmt, parent as IStatementContainer),
|
||||
IAstModification.ReplaceNode(gosub, Jump(gosub.address, gosub.identifier, gosub.generatedLabel, gosub.position), parent)
|
||||
IAstModification.ReplaceNode(gosub, Jump(null, gosub.identifier, null, gosub.position), parent)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,13 +222,7 @@ class IntermediateAstMaker(val program: Program) {
|
||||
return call
|
||||
}
|
||||
|
||||
private fun transform(gosub: GoSub): PtGosub {
|
||||
val identifier = if(gosub.identifier!=null) transform(gosub.identifier!!) else null
|
||||
return PtGosub(identifier,
|
||||
gosub.address,
|
||||
gosub.generatedLabel,
|
||||
gosub.position)
|
||||
}
|
||||
private fun transform(gosub: GoSub): PtGosub = PtGosub(transform(gosub.identifier), gosub.position)
|
||||
|
||||
private fun transform(srcIf: IfElse): PtIfElse {
|
||||
val ifelse = PtIfElse(srcIf.position)
|
||||
|
||||
@@ -183,18 +183,12 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(gosub: GoSub) {
|
||||
val ident = gosub.identifier
|
||||
if(ident!=null) {
|
||||
val targetStatement = checkFunctionOrLabelExists(ident, gosub)
|
||||
if(targetStatement!=null) {
|
||||
if(targetStatement is BuiltinFunctionPlaceholder)
|
||||
errors.err("can't gosub to a builtin function", gosub.position)
|
||||
}
|
||||
val targetStatement = checkFunctionOrLabelExists(gosub.identifier, gosub)
|
||||
if(targetStatement!=null) {
|
||||
if(targetStatement is BuiltinFunctionPlaceholder)
|
||||
errors.err("can't gosub to a builtin function", gosub.position)
|
||||
}
|
||||
|
||||
val addr = gosub.address
|
||||
if(addr!=null && addr > 65535u)
|
||||
errors.err("gosub address must be valid integer 0..\$ffff", gosub.position)
|
||||
super.visit(gosub)
|
||||
}
|
||||
|
||||
|
||||
@@ -411,21 +411,22 @@ internal class StatementReorderer(val program: Program,
|
||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
val function = functionCallStatement.target.targetStatement(program)!!
|
||||
checkUnusedReturnValues(functionCallStatement, function, program, errors)
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun tryReplaceCallWithGosub(functionCallStatement: FunctionCallStatement,
|
||||
parent: Node,
|
||||
program: Program,
|
||||
options: CompilationOptions): Iterable<IAstModification> {
|
||||
internal fun tryReplaceCallWithGosub(
|
||||
functionCallStatement: FunctionCallStatement,
|
||||
parent: Node,
|
||||
program: Program
|
||||
): Iterable<IAstModification> {
|
||||
val callee = functionCallStatement.target.targetStatement(program)!!
|
||||
if(callee is Subroutine) {
|
||||
if(callee.inline)
|
||||
return emptyList()
|
||||
return if(callee.isAsmSubroutine)
|
||||
tryReplaceCallAsmSubWithGosub(functionCallStatement, parent, callee, options.compTarget)
|
||||
tryReplaceCallAsmSubWithGosub(functionCallStatement, parent, callee)
|
||||
else
|
||||
tryReplaceCallNormalSubWithGosub(functionCallStatement, parent, callee, program)
|
||||
}
|
||||
@@ -437,7 +438,7 @@ private fun tryReplaceCallNormalSubWithGosub(call: FunctionCallStatement, parent
|
||||
|
||||
if(callee.parameters.isEmpty()) {
|
||||
// 0 params -> just GoSub
|
||||
return listOf(IAstModification.ReplaceNode(call, GoSub(null, call.target, null, call.position), parent))
|
||||
return listOf(IAstModification.ReplaceNode(call, GoSub(call.target, call.position), parent))
|
||||
}
|
||||
|
||||
if(callee.parameters.size==1) {
|
||||
@@ -466,14 +467,14 @@ private fun tryReplaceCallNormalSubWithGosub(call: FunctionCallStatement, parent
|
||||
Assignment(AssignTarget(paramIdentifier, null, null, argumentValue.position), argumentValue, AssignmentOrigin.PARAMETERASSIGN, argumentValue.position)
|
||||
}
|
||||
val scope = AnonymousScope(assignParams.toMutableList(), call.position)
|
||||
scope.statements += GoSub(null, call.target, null, call.position)
|
||||
scope.statements += GoSub(call.target, call.position)
|
||||
return listOf(IAstModification.ReplaceNode(call, scope, parent))
|
||||
}
|
||||
|
||||
private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
|
||||
parent: Node,
|
||||
callee: Subroutine,
|
||||
compTarget: ICompilationTarget
|
||||
private fun tryReplaceCallAsmSubWithGosub(
|
||||
call: FunctionCallStatement,
|
||||
parent: Node,
|
||||
callee: Subroutine
|
||||
): Iterable<IAstModification> {
|
||||
val noModifications = emptyList<IAstModification>()
|
||||
|
||||
@@ -483,7 +484,7 @@ private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
|
||||
if(callee.shouldSaveX()) {
|
||||
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rsavex"), call.position), mutableListOf(), true, call.position)
|
||||
}
|
||||
scope.statements += GoSub(null, call.target, null, call.position)
|
||||
scope.statements += GoSub(call.target, call.position)
|
||||
if(callee.shouldSaveX()) {
|
||||
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), call.position), mutableListOf(), true, call.position)
|
||||
}
|
||||
@@ -495,15 +496,16 @@ private fun tryReplaceCallAsmSubWithGosub(call: FunctionCallStatement,
|
||||
return noModifications
|
||||
} else {
|
||||
// clobber risk; evaluate the arguments on the CPU stack first (in reverse order)...
|
||||
return makeGosubWithArgsViaCpuStack(call, call.position, parent, callee, compTarget)
|
||||
return makeGosubWithArgsViaCpuStack(call, call.position, parent, callee)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeGosubWithArgsViaCpuStack(call: IFunctionCall,
|
||||
position: Position,
|
||||
parent: Node,
|
||||
callee: Subroutine,
|
||||
compTarget: ICompilationTarget): Iterable<IAstModification> {
|
||||
private fun makeGosubWithArgsViaCpuStack(
|
||||
call: IFunctionCall,
|
||||
position: Position,
|
||||
parent: Node,
|
||||
callee: Subroutine
|
||||
): Iterable<IAstModification> {
|
||||
|
||||
fun popCall(targetName: List<String>, dt: DataType, position: Position): FunctionCallStatement {
|
||||
return FunctionCallStatement(
|
||||
@@ -545,7 +547,7 @@ private fun makeGosubWithArgsViaCpuStack(call: IFunctionCall,
|
||||
val targetName = callee.scopedName + param.name
|
||||
scope.statements += popCall(targetName, param.type, position)
|
||||
}
|
||||
scope.statements += GoSub(null, call.target, null, position)
|
||||
scope.statements += GoSub(call.target, position)
|
||||
if(callee.shouldSaveX()) {
|
||||
scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), position), mutableListOf(), true, position)
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ internal class VariousCleanups(val program: Program, val errors: IErrorReporter,
|
||||
}
|
||||
|
||||
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program, options)
|
||||
return tryReplaceCallWithGosub(functionCallStatement, parent, program)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -242,11 +242,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
|
||||
override fun visit(gosub: GoSub) {
|
||||
output("gosub ")
|
||||
when {
|
||||
gosub.address!=null -> output(gosub.address.toHex())
|
||||
gosub.generatedLabel!=null -> output(gosub.generatedLabel)
|
||||
gosub.identifier!=null -> gosub.identifier.accept(this)
|
||||
}
|
||||
gosub.identifier.accept(this)
|
||||
}
|
||||
|
||||
override fun visit(ifElse: IfElse) {
|
||||
|
||||
@@ -583,25 +583,22 @@ class Jump(var address: UInt?,
|
||||
"Jump(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
|
||||
}
|
||||
|
||||
// a GoSub is ONLY created internally for calling subroutines
|
||||
class GoSub(val address: UInt?,
|
||||
val identifier: IdentifierReference?,
|
||||
val generatedLabel: String?, // can be used in code generation scenarios
|
||||
override val position: Position) : Statement() {
|
||||
// a GoSub is ONLY created internally for calling subroutines, there's no syntax for it in the language
|
||||
class GoSub(val identifier: IdentifierReference, override val position: Position) : Statement() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
identifier?.linkParents(this)
|
||||
identifier.linkParents(this)
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun copy() = GoSub(address, identifier?.copy(), generatedLabel, position)
|
||||
override fun copy() = GoSub(identifier.copy(), position)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
override fun toString() =
|
||||
"GoSub(addr: $address, identifier: $identifier, label: $generatedLabel; pos=$position)"
|
||||
"GoSub($identifier; pos=$position)"
|
||||
}
|
||||
|
||||
class FunctionCallStatement(override var target: IdentifierReference,
|
||||
|
||||
@@ -300,7 +300,7 @@ abstract class AstWalker {
|
||||
|
||||
fun visit(gosub: GoSub, parent: Node) {
|
||||
track(before(gosub, parent), gosub, parent)
|
||||
gosub.identifier?.accept(this, gosub)
|
||||
gosub.identifier.accept(this, gosub)
|
||||
track(after(gosub, parent), gosub, parent)
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ interface IAstVisitor {
|
||||
}
|
||||
|
||||
fun visit(gosub: GoSub) {
|
||||
gosub.identifier?.accept(this)
|
||||
gosub.identifier.accept(this)
|
||||
}
|
||||
|
||||
fun visit(ifElse: IfElse) {
|
||||
|
||||
@@ -101,7 +101,7 @@ class CallGraph(private val program: Program, private val allowMissingIdentifier
|
||||
}
|
||||
|
||||
override fun visit(gosub: GoSub) {
|
||||
val otherSub = gosub.identifier?.targetSubroutine(program)
|
||||
val otherSub = gosub.identifier.targetSubroutine(program)
|
||||
if (otherSub != null) {
|
||||
gosub.definingSubroutine?.let { thisSub ->
|
||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
||||
|
||||
Reference in New Issue
Block a user