mirror of
https://github.com/irmen/prog8.git
synced 2025-01-10 20:30:23 +00:00
allow "goto pointervar" for indirect jumps
This commit is contained in:
parent
c8bd57cd4d
commit
9219ec539d
@ -875,7 +875,10 @@ class AsmGen(private val program: Program,
|
||||
}
|
||||
}
|
||||
is Assignment -> assignmentAsmGen.translate(stmt)
|
||||
is Jump -> jmp(getJumpTarget(stmt))
|
||||
is Jump -> {
|
||||
val (asmLabel, indirect) = getJumpTarget(stmt)
|
||||
jmp(asmLabel, indirect)
|
||||
}
|
||||
is GoSub -> translate(stmt)
|
||||
is PostIncrDecr -> postincrdecrAsmGen.translate(stmt)
|
||||
is Label -> translate(stmt)
|
||||
@ -1563,7 +1566,17 @@ $repeatLabel lda $counterVar
|
||||
if(jump!=null) {
|
||||
// branch with only a jump (goto)
|
||||
val instruction = branchInstruction(stmt.condition, false)
|
||||
out(" $instruction ${getJumpTarget(jump)}")
|
||||
val (asmLabel, indirect) = getJumpTarget(jump)
|
||||
if(indirect) {
|
||||
val complementedInstruction = branchInstruction(stmt.condition, true)
|
||||
out("""
|
||||
$complementedInstruction +
|
||||
jmp ($asmLabel)
|
||||
+""")
|
||||
}
|
||||
else {
|
||||
out(" $instruction $asmLabel")
|
||||
}
|
||||
translate(stmt.elsepart)
|
||||
} else {
|
||||
if(stmt.elsepart.isEmpty()) {
|
||||
@ -1638,15 +1651,22 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
}
|
||||
|
||||
private fun getJumpTarget(jump: Jump): String {
|
||||
private fun getJumpTarget(jump: Jump): Pair<String, Boolean> {
|
||||
val ident = jump.identifier
|
||||
val label = jump.generatedLabel
|
||||
val addr = jump.address
|
||||
return when {
|
||||
ident!=null -> asmSymbolName(ident)
|
||||
label!=null -> label
|
||||
addr!=null -> addr.toHex()
|
||||
else -> "????"
|
||||
ident!=null -> {
|
||||
// can be a label, or a pointer variable
|
||||
val target = ident.targetVarDecl(program)
|
||||
if(target!=null)
|
||||
Pair(asmSymbolName(ident), true) // indirect
|
||||
else
|
||||
Pair(asmSymbolName(ident), false)
|
||||
}
|
||||
label!=null -> Pair(label, false)
|
||||
addr!=null -> Pair(addr.toHex(), false)
|
||||
else -> Pair("????", false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1758,11 +1778,15 @@ $repeatLabel lda $counterVar
|
||||
return zeropage.allocatedZeropageVariable(vardecl.scopedName)!=null
|
||||
}
|
||||
|
||||
internal fun jmp(asmLabel: String) {
|
||||
if(isTargetCpu(CpuType.CPU65c02))
|
||||
out(" bra $asmLabel") // note: 64tass will convert this automatically to a jmp if the relative distance is too large
|
||||
else
|
||||
out(" jmp $asmLabel")
|
||||
internal fun jmp(asmLabel: String, indirect: Boolean=false) {
|
||||
if(indirect) {
|
||||
out(" jmp ($asmLabel)")
|
||||
} else {
|
||||
if (isTargetCpu(CpuType.CPU65c02))
|
||||
out(" bra $asmLabel") // note: 64tass will convert this automatically to a jmp if the relative distance is too large
|
||||
else
|
||||
out(" jmp $asmLabel")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair<Expression, Expression>? {
|
||||
|
@ -1308,8 +1308,18 @@ internal class AstChecker(private val program: Program,
|
||||
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
|
||||
when (val targetStatement = target.targetStatement(program)) {
|
||||
is Label, is Subroutine, is BuiltinFunctionPlaceholder -> return targetStatement
|
||||
null -> errors.err("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", statement.position)
|
||||
else -> errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", statement.position)
|
||||
is VarDecl -> {
|
||||
if(statement is Jump) {
|
||||
if (targetStatement.datatype == DataType.UWORD)
|
||||
return targetStatement
|
||||
else
|
||||
errors.err("wrong address variable datatype, expected uword", target.position)
|
||||
}
|
||||
else
|
||||
errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position)
|
||||
}
|
||||
null -> errors.err("undefined function or subroutine: ${target.nameInSource.joinToString(".")}", target.position)
|
||||
else -> errors.err("cannot call that: ${target.nameInSource.joinToString(".")}", target.position)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
@ -332,4 +332,57 @@ class TestScoping: FunSpec({
|
||||
errors.errors[3] shouldContain "undefined symbol: routine.nested.nestedvalue"
|
||||
errors.errors[4] shouldContain "undefined symbol: nested.nestedvalue"
|
||||
}
|
||||
|
||||
test("various good goto targets") {
|
||||
val text="""
|
||||
main {
|
||||
sub start() {
|
||||
uword address = $4000
|
||||
|
||||
goto ${'$'}c000
|
||||
goto address ; indirect jump
|
||||
goto main.routine
|
||||
goto main.jumplabel
|
||||
|
||||
if_cc
|
||||
goto ${'$'}c000
|
||||
if_cc
|
||||
goto address ; indirect jump
|
||||
if_cc
|
||||
goto main.routine
|
||||
if_cc
|
||||
goto main.jumplabel
|
||||
}
|
||||
|
||||
jumplabel:
|
||||
%asm {{
|
||||
rts
|
||||
}}
|
||||
sub routine() {
|
||||
}
|
||||
}
|
||||
"""
|
||||
compileText(C64Target, false, text, writeAssembly = false).assertSuccess()
|
||||
}
|
||||
|
||||
test("various wrong goto targets") {
|
||||
val text = """
|
||||
main {
|
||||
sub start() {
|
||||
byte wrongaddress = 100
|
||||
|
||||
goto wrongaddress ; must be uword
|
||||
goto main.routine ; can't take args
|
||||
}
|
||||
|
||||
sub routine(ubyte arg) {
|
||||
}
|
||||
}
|
||||
"""
|
||||
val errors = ErrorReporterForTests()
|
||||
compileText(C64Target, false, text, writeAssembly = false, errors = errors).assertFailure()
|
||||
errors.errors.size shouldBe 2
|
||||
errors.errors[0] shouldContain "wrong address"
|
||||
errors.errors[1] shouldContain "takes parameters"
|
||||
}
|
||||
})
|
||||
|
@ -231,7 +231,7 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
override fun visit(jump: Jump) {
|
||||
output("goto ")
|
||||
when {
|
||||
jump.address!=null -> output(jump.address.toHex())
|
||||
jump.address!=null -> output(jump.address!!.toHex())
|
||||
jump.generatedLabel!=null -> output(jump.generatedLabel)
|
||||
jump.identifier!=null -> jump.identifier.accept(this)
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ class PostIncrDecr(var target: AssignTarget, val operator: String, override val
|
||||
override fun toString() = "PostIncrDecr(op: $operator, target: $target, pos=$position)"
|
||||
}
|
||||
|
||||
class Jump(val address: UInt?,
|
||||
class Jump(var address: UInt?,
|
||||
val identifier: IdentifierReference?,
|
||||
val generatedLabel: String?, // can be used in code generation scenarios
|
||||
override val position: Position) : Statement() {
|
||||
@ -538,7 +538,13 @@ class Jump(val address: UInt?,
|
||||
identifier?.linkParents(this)
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
if(node===identifier && replacement is NumericLiteralValue) {
|
||||
address = replacement.number.toUInt()
|
||||
}
|
||||
else
|
||||
throw FatalAstException("can't replace $node")
|
||||
}
|
||||
override fun copy() = Jump(address, identifier?.copy(), generatedLabel, position)
|
||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
@ -784,10 +784,15 @@ of a label or subroutine::
|
||||
goto $c000 ; address
|
||||
goto name ; label or subroutine
|
||||
|
||||
uword address = $4000
|
||||
goto address ; jump via address variable
|
||||
|
||||
Notice that this is a valid way to end a subroutine (you can either ``return`` from it, or jump
|
||||
to another piece of code that eventually returns).
|
||||
|
||||
If you jump to an address variable (uword), it is doing an 'indirect' jump: the jump will be done
|
||||
to the address that's currently in the variable.
|
||||
|
||||
|
||||
Conditional execution
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -3,7 +3,6 @@ TODO
|
||||
|
||||
For next release
|
||||
^^^^^^^^^^^^^^^^
|
||||
- allow goto pointervar (goto $a000 already works...) then use this in cx16assem's run_file()
|
||||
- allow "xxx" * constexpr (where constexpr is not a number literal, now gives expression error not same type)
|
||||
- is * lower prio than bitwise & ? fix prios if so!
|
||||
|
||||
|
@ -3,16 +3,20 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
cx16.mouse_config(1, 0)
|
||||
txt.print("yo\n")
|
||||
uword jumps = $4000
|
||||
if_cc
|
||||
goto jumps
|
||||
|
||||
repeat {
|
||||
ubyte mb = cx16.mouse_pos()
|
||||
txt.print_uw(cx16.r0)
|
||||
txt.spc()
|
||||
txt.print_uw(cx16.r1)
|
||||
txt.spc()
|
||||
txt.print_ub(mb)
|
||||
txt.nl()
|
||||
}
|
||||
goto jumps
|
||||
}
|
||||
}
|
||||
|
||||
test $4000 {
|
||||
%option force_output
|
||||
|
||||
jumper:
|
||||
%asm {{
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user