From cc59069876539981db35a644b0d4e6ee5b8e7133 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 14 Dec 2024 00:56:11 +0100 Subject: [PATCH] allow goto to take any expression, not only an integer or an identifier (part 1) --- codeCore/src/prog8/code/ast/AstPrinter.kt | 7 +- codeCore/src/prog8/code/ast/AstStatements.kt | 6 +- .../src/prog8/codegen/cpu6502/AsmGen.kt | 41 +++++----- .../prog8/codegen/intermediate/IRCodeGen.kt | 78 ++++++++++++------- codeGenIntermediate/test/TestVmCodeGen.kt | 8 +- .../compiler/astprocessing/AstChecker.kt | 18 +++-- .../astprocessing/IntermediateAstMaker.kt | 8 +- .../IntermediateAstPostprocess.kt | 7 +- .../src/prog8/ast/AstToSourceTextConverter.kt | 5 +- compilerAst/src/prog8/ast/Program.kt | 3 +- .../src/prog8/ast/antlr/Antlr2Kotlin.kt | 4 +- .../src/prog8/ast/statements/AstStatements.kt | 16 ++-- compilerAst/src/prog8/ast/walk/AstWalker.kt | 2 +- compilerAst/src/prog8/ast/walk/IAstVisitor.kt | 2 +- compilerAst/src/prog8/compiler/CallGraph.kt | 2 +- docs/source/todo.rst | 4 + examples/test.p8 | 28 +------ parser/src/main/antlr/Prog8ANTLR.g4 | 2 +- 18 files changed, 122 insertions(+), 119 deletions(-) diff --git a/codeCore/src/prog8/code/ast/AstPrinter.kt b/codeCore/src/prog8/code/ast/AstPrinter.kt index 2cead573a..defd79957 100644 --- a/codeCore/src/prog8/code/ast/AstPrinter.kt +++ b/codeCore/src/prog8/code/ast/AstPrinter.kt @@ -68,12 +68,7 @@ fun printAst(root: PtNode, skipLibraries: Boolean, output: (text: String) -> Uni "%asm {{ ...${node.assembly.length} characters... }}" } is PtJump -> { - if(node.identifier!=null) - "goto ${node.identifier.name}" - else if(node.address!=null) - "goto ${node.address.toHex()}" - else - "???" + "goto ${txt(node.target)}" } is PtAsmSub -> { val params = node.parameters.joinToString(", ") { diff --git a/codeCore/src/prog8/code/ast/AstStatements.kt b/codeCore/src/prog8/code/ast/AstStatements.kt index 318f6802f..d15985c8e 100644 --- a/codeCore/src/prog8/code/ast/AstStatements.kt +++ b/codeCore/src/prog8/code/ast/AstStatements.kt @@ -116,11 +116,9 @@ class PtIfElse(position: Position) : PtNode(position) { } -class PtJump(val identifier: PtIdentifier?, // note: even ad-hoc labels are wrapped as an Identifier to simplify code. Just use dummy type and position. - val address: UInt?, - position: Position) : PtNode(position) { +class PtJump(val target: PtExpression, position: Position) : PtNode(position) { init { - identifier?.let {it.parent = this } + target.parent = this } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index c1c0caf1c..c78963e8b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -74,8 +74,9 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque } } is PtJump -> { - if(node.address==null) { - val stNode = st.lookup(node.identifier!!.name) ?: throw AssemblyError("name not found ${node.identifier}") + val identifier = node.target as? PtIdentifier + if(identifier!=null) { + val stNode = st.lookup(identifier.name) ?: throw AssemblyError("name not found $identifier") if (stNode.astNode.definingBlock()?.options?.noSymbolPrefixing != true) { val index = node.parent.children.indexOf(node) nodesToPrefix += node.parent to index @@ -177,10 +178,14 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable { } private fun PtJump.prefix(parent: PtNode, st: SymbolTable): PtJump { - val prefixedIdent = identifier!!.prefix(this, st) - val jump = PtJump(prefixedIdent, address, position) - jump.parent = parent - return jump + val identifier = target as? PtIdentifier + if(identifier!=null) { + val prefixedIdent = identifier.prefix(this, st) + val jump = PtJump(prefixedIdent, position) + jump.parent = parent + return jump + } + return this } private fun PtFunctionCall.prefix(parent: PtNode): PtFunctionCall { @@ -1034,20 +1039,18 @@ $repeatLabel""") } internal fun getJumpTarget(jump: PtJump): Pair { - val ident = jump.identifier - val addr = jump.address - return when { - ident!=null -> { - // can be a label, or a pointer variable - val symbol = symbolTable.lookup(ident.name) - if(symbol?.type in arrayOf(StNodeType.STATICVAR, StNodeType.MEMVAR, StNodeType.CONSTANT)) - Pair(asmSymbolName(ident), true) // indirect jump if the jump symbol is a variable - else - Pair(asmSymbolName(ident), false) - } - addr!=null -> Pair(addr.toHex(), false) - else -> Pair("????", false) + val ident = jump.target as? PtIdentifier + if(ident!=null) { + // can be a label, or a pointer variable + val symbol = symbolTable.lookup(ident.name) + return if(symbol?.type in arrayOf(StNodeType.STATICVAR, StNodeType.MEMVAR, StNodeType.CONSTANT)) + Pair(asmSymbolName(ident), true) // indirect jump if the jump symbol is a variable + else + Pair(asmSymbolName(ident), false) } + val addr = jump.target.asConstInteger() + if(addr!=null) return Pair(addr.toHex(), false) + else TODO("GOTO TARGET ${jump.target}") } private fun translate(ret: PtReturn) { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt index 45d83d040..d6cc170c1 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt @@ -277,7 +277,8 @@ class IRCodeGen( val goto = branch.trueScope.children.firstOrNull() as? PtJump if (goto is PtJump) { // special case the form: if_cc goto (with optional else) - val address = goto.address?.toInt() + val address = goto.target.asConstInteger() + val label = (goto.target as? PtIdentifier)?.name if(address!=null) { val branchIns = when(branch.condition) { BranchCondition.CS -> IRInstruction(Opcode.BSTCS, address = address) @@ -290,8 +291,7 @@ class IRCodeGen( BranchCondition.VS -> IRInstruction(Opcode.BSTVS, address = address) } addInstr(result, branchIns, null) - } else { - val label = goto.identifier!!.name + } else if(label!=null) { val branchIns = when(branch.condition) { BranchCondition.CS -> IRInstruction(Opcode.BSTCS, labelSymbol = label) BranchCondition.CC -> IRInstruction(Opcode.BSTCC, labelSymbol = label) @@ -303,6 +303,8 @@ class IRCodeGen( BranchCondition.VS -> IRInstruction(Opcode.BSTVS, labelSymbol = label) } addInstr(result, branchIns, null) + } else { + TODO("GOTO TARGET ${goto.target}") } if(branch.falseScope.children.isNotEmpty()) result += translateNode(branch.falseScope) @@ -1025,7 +1027,12 @@ class IRCodeGen( it += IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = afterIfLabel) } } - it += IRInstruction(Opcode.JUMPI, labelSymbol = goto.identifier!!.name) + val identifier = goto.target as? PtIdentifier + if(identifier!=null) { + it += IRInstruction(Opcode.JUMPI, labelSymbol = identifier.name) + } else { + TODO("GOTO TARGET ${goto.target}") + } } else { // normal jump, directly to target with branch opcode when(condition.operator) { @@ -1045,10 +1052,12 @@ class IRCodeGen( ">=" -> Opcode.BGES else -> throw AssemblyError("weird operator") } - it += if (goto.address != null) - IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, address = goto.address?.toInt()) + it += if (goto.target.asConstInteger() != null) + IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, address = goto.target.asConstInteger()) + else if(goto.target is PtIdentifier) + IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = (goto.target as PtIdentifier).name) else - IRInstruction(gotoOpcode, IRDataType.BYTE, reg1 = compResultReg, immediate = 0, labelSymbol = goto.identifier!!.name) + TODO("GOTO TARGET ${goto.target}") } } } @@ -1059,11 +1068,15 @@ class IRCodeGen( } private fun branchInstr(goto: PtJump, branchOpcode: Opcode): IRInstruction { - return if (goto.address != null) - IRInstruction(branchOpcode, address = goto.address?.toInt()) + return if (goto.target.asConstInteger() != null) + IRInstruction(branchOpcode, address = goto.target.asConstInteger()) else { require(!isIndirectJump(goto)) { "indirect jumps cannot be expressed using a branch opcode"} - IRInstruction(branchOpcode, labelSymbol = goto.identifier!!.name) + val identifier = goto.target as? PtIdentifier + if(identifier!=null) + IRInstruction(branchOpcode, labelSymbol = identifier.name) + else + TODO("GOTO TARGET ${goto.target}") } } @@ -1071,7 +1084,11 @@ class IRCodeGen( // indirect jump to target so the if has to jump past it instead val result = mutableListOf() val afterIfLabel = createLabelName() - val gotoSymbol = goto.identifier!!.name + val identifier = goto.target as? PtIdentifier + if(identifier==null) { + TODO("GOTO TARGET ${goto.target}") + } + val gotoSymbol = identifier.name fun ifNonZeroIntThenJump_BinExpr(condition: PtBinaryExpression) { if(condition.operator in LogicalOperators) { @@ -1235,10 +1252,12 @@ class IRCodeGen( ">=" -> if(signed) Opcode.BGES else Opcode.BGE else -> throw AssemblyError("invalid comparison operator") } - if (goto.address != null) - addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, address = goto.address?.toInt()), null) + if (goto.target.asConstInteger() != null) + addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, address = goto.target.asConstInteger()), null) + else if(goto.target is PtIdentifier) + addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, labelSymbol = (goto.target as PtIdentifier).name), null) else - addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, immediate = number, labelSymbol = goto.identifier!!.name), null) + TODO("GOTO TARGET ${goto.target}") } } } else { @@ -1292,10 +1311,12 @@ class IRCodeGen( it += branchInstr(goto, opcode) } } else { - if (goto.address != null) - addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, address = goto.address?.toInt()), null) + if (goto.target.asConstInteger() != null) + addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, address = goto.target.asConstInteger()), null) + else if(goto.target is PtIdentifier) + addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, labelSymbol = (goto.target as PtIdentifier).name), null) else - addInstr(result, IRInstruction(opcode, irDt, reg1 = firstReg, reg2 = secondReg, labelSymbol = goto.identifier!!.name), null) + TODO("GOTO TARGET ${goto.target}") } } } @@ -1628,26 +1649,31 @@ class IRCodeGen( private fun translate(jump: PtJump): IRCodeChunks { val result = mutableListOf() val chunk = IRCodeChunk(null, null) - chunk += if(jump.address!=null) { - IRInstruction(Opcode.JUMP, address = jump.address!!.toInt()) + chunk += if(jump.target.asConstInteger()!=null) { + IRInstruction(Opcode.JUMP, address = jump.target.asConstInteger()) } else { - if (jump.identifier != null) { + val identifier = jump.target as? PtIdentifier + if (identifier != null) { if(isIndirectJump(jump)) { - IRInstruction(Opcode.JUMPI, labelSymbol = jump.identifier!!.name) + IRInstruction(Opcode.JUMPI, labelSymbol = identifier.name) } else { - IRInstruction(Opcode.JUMP, labelSymbol = jump.identifier!!.name) + IRInstruction(Opcode.JUMP, labelSymbol = identifier.name) } - } else - throw AssemblyError("weird jump") + } else { + TODO("GOTO TARGET ${jump.target}") + } } result += chunk return result } private fun isIndirectJump(jump: PtJump): Boolean { - if(jump.identifier==null) + if(jump.target.asConstInteger()!=null) return false - val symbol = symbolTable.lookup(jump.identifier!!.name) + val identifier = jump.target as? PtIdentifier + if(identifier==null) + return true + val symbol = symbolTable.lookup(identifier.name) return symbol?.type==StNodeType.MEMVAR || symbol?.type==StNodeType.STATICVAR } diff --git a/codeGenIntermediate/test/TestVmCodeGen.kt b/codeGenIntermediate/test/TestVmCodeGen.kt index a229fd6f7..1b56592f7 100644 --- a/codeGenIntermediate/test/TestVmCodeGen.kt +++ b/codeGenIntermediate/test/TestVmCodeGen.kt @@ -312,7 +312,7 @@ class TestVmCodeGen: FunSpec({ cmp1.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) cmp1.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if1.add(cmp1) - if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) + if1.add(PtNodeGroup().also { it.add(PtJump(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) }) if1.add(PtNodeGroup()) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) @@ -320,7 +320,7 @@ class TestVmCodeGen: FunSpec({ cmp2.add(PtIdentifier("main.start.f1", DataType.forDt(BaseDataType.FLOAT), Position.DUMMY)) cmp2.add(PtNumber(BaseDataType.FLOAT, 42.0, Position.DUMMY)) if2.add(cmp2) - if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) + if2.add(PtNodeGroup().also { it.add(PtJump(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) }) if2.add(PtNodeGroup()) sub.add(if2) block.add(sub) @@ -505,7 +505,7 @@ class TestVmCodeGen: FunSpec({ cmp1.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)) cmp1.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY)) if1.add(cmp1) - if1.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) + if1.add(PtNodeGroup().also { it.add(PtJump(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) }) if1.add(PtNodeGroup()) sub.add(if1) val if2 = PtIfElse(Position.DUMMY) @@ -513,7 +513,7 @@ class TestVmCodeGen: FunSpec({ cmp2.add(PtIdentifier("main.start.ub1", DataType.forDt(BaseDataType.UBYTE), Position.DUMMY)) cmp2.add(PtNumber(BaseDataType.UBYTE, 42.0, Position.DUMMY)) if2.add(cmp2) - if2.add(PtNodeGroup().also { it.add(PtJump(null, 0xc000u, Position.DUMMY)) }) + if2.add(PtNodeGroup().also { it.add(PtJump(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) }) if2.add(PtNodeGroup()) sub.add(if2) block.add(sub) diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 01f124f99..b5b21a109 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -259,7 +259,7 @@ internal class AstChecker(private val program: Program, } override fun visit(jump: Jump) { - val ident = jump.identifier + val ident = jump.target as? IdentifierReference if(ident!=null) { val targetStatement = ident.checkFunctionOrLabelExists(program, jump, errors) if(targetStatement!=null) { @@ -269,11 +269,15 @@ internal class AstChecker(private val program: Program, if(targetStatement is Subroutine && targetStatement.parameters.any()) { errors.err("can't jump to a subroutine that takes parameters", jump.position) } - } + } else { + val addr = jump.target.constValue(program)?.number + if (addr!=null && (addr<0 || addr > 65535)) + errors.err("goto address must be uword", jump.position) - val addr = jump.address - if(addr!=null && addr > 65535u) - errors.err("jump address must be valid integer 0..\$ffff", jump.position) + val addressDt = jump.target.inferType(program).getOrUndef() + if(!(addressDt.isUnsignedByte || addressDt.isUnsignedWord)) + errors.err("goto address must be uword", jump.position) + } super.visit(jump) } @@ -340,7 +344,7 @@ internal class AstChecker(private val program: Program, count++ } override fun visit(jump: Jump) { - val jumpTarget = jump.identifier?.targetStatement(program) + val jumpTarget = (jump.target as? IdentifierReference)?.targetStatement(program) if(jumpTarget!=null) { val sub = jump.definingSubroutine val targetSub = jumpTarget as? Subroutine ?: jumpTarget.definingSubroutine @@ -1177,7 +1181,7 @@ internal class AstChecker(private val program: Program, count++ } override fun visit(jump: Jump) { - val jumpTarget = jump.identifier?.targetStatement(program) + val jumpTarget = (jump.target as? IdentifierReference)?.targetStatement(program) if(jumpTarget!=null) { val sub = jump.definingSubroutine val targetSub = jumpTarget as? Subroutine ?: jumpTarget.definingSubroutine diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt index a749ff24e..ffc6c4c2e 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstMaker.kt @@ -377,7 +377,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr val scopedEndLabel = (srcIf.definingScope.scopedName + endLabel).joinToString(".") val elseLbl = PtIdentifier(scopedElseLabel, DataType.forDt(BaseDataType.UNDEFINED), srcIf.position) val endLbl = PtIdentifier(scopedEndLabel, DataType.forDt(BaseDataType.UNDEFINED), srcIf.position) - ifScope.add(PtJump(elseLbl, null, srcIf.position)) + ifScope.add(PtJump(elseLbl, srcIf.position)) val elseScope = PtNodeGroup() branch.add(ifScope) branch.add(elseScope) @@ -385,7 +385,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr for (stmt in srcIf.truepart.statements) nodes.add(transformStatement(stmt)) if(srcIf.elsepart.isNotEmpty()) - nodes.add(PtJump(endLbl, null, srcIf.position)) + nodes.add(PtJump(endLbl, srcIf.position)) nodes.add(PtLabel(elseLabel, srcIf.position)) if(srcIf.elsepart.isNotEmpty()) { for (stmt in srcIf.elsepart.statements) @@ -449,8 +449,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr } private fun transform(srcJump: Jump): PtJump { - val identifier = if(srcJump.identifier!=null) transform(srcJump.identifier!!) else null - return PtJump(identifier, srcJump.address, srcJump.position) + val target = transformExpression(srcJump.target) + return PtJump(target, srcJump.position) } private fun transform(label: Label): PtLabel = diff --git a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt index ab63910c1..6a0bca7f1 100644 --- a/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt +++ b/compiler/src/prog8/compiler/astprocessing/IntermediateAstPostprocess.kt @@ -91,8 +91,9 @@ private fun integrateDefers(subdefers: Map>, program: PtPro jumpsAndCallsToAugment.add(node) } is PtJump -> { - if (node.identifier != null) { - val stNode = st.lookup(node.identifier!!.name)!! + val identifier = node.target as? PtIdentifier + if (identifier != null) { + val stNode = st.lookup(identifier.name)!! val targetSub = stNode.astNode.definingSub() if (targetSub != node.definingSub()) jumpsAndCallsToAugment.add(node) @@ -188,7 +189,7 @@ private fun integrateDefers(subdefers: Map>, program: PtPro val skiplabel = "prog8_defer_skip_${idx+1}" val branchcc = PtConditionalBranch(BranchCondition.CC, Position.DUMMY) branchcc.add(PtNodeGroup().also { - it.add(PtJump(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.forDt(BaseDataType.UBYTE), Position.DUMMY), null, Position.DUMMY)) + it.add(PtJump(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.forDt(BaseDataType.UBYTE), Position.DUMMY), Position.DUMMY)) }) branchcc.add(PtNodeGroup()) defersRoutine.add(branchcc) diff --git a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt index 43cf3475f..64654433e 100644 --- a/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt +++ b/compilerAst/src/prog8/ast/AstToSourceTextConverter.kt @@ -261,10 +261,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.identifier!=null -> jump.identifier.accept(this) - } + jump.target.accept(this) } override fun visit(ifElse: IfElse) { diff --git a/compilerAst/src/prog8/ast/Program.kt b/compilerAst/src/prog8/ast/Program.kt index 2360719b8..36ab6efee 100644 --- a/compilerAst/src/prog8/ast/Program.kt +++ b/compilerAst/src/prog8/ast/Program.kt @@ -159,7 +159,6 @@ class Program(val name: String, } fun jumpLabel(label: Label): Jump { - val ident = IdentifierReference(listOf(label.name), label.position) - return Jump(null, ident, label.position) + return Jump(IdentifierReference(listOf(label.name), label.position), label.position) } } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index 039af3501..505fa814a 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -301,9 +301,7 @@ private fun ReturnstmtContext.toAst() : Return { } private fun UnconditionaljumpContext.toAst(): Jump { - val address = integerliteral()?.toAst()?.number?.toUInt() - val identifier = scoped_identifier()?.toAst() - return Jump(address, identifier, toPosition()) + return Jump(expression().toAst(), toPosition()) } private fun LabeldefContext.toAst(): Statement = diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index ce8e78f13..72306ce56 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -679,30 +679,28 @@ data class AssignTarget(var identifier: IdentifierReference?, } -class Jump(var address: UInt?, - val identifier: IdentifierReference?, - override val position: Position) : Statement() { +class Jump(var target: Expression, override val position: Position) : Statement() { override lateinit var parent: Node override fun linkParents(parent: Node) { this.parent = parent - identifier?.linkParents(this) + target.linkParents(this) } override fun replaceChildNode(node: Node, replacement: Node) { - if(node===identifier && replacement is NumericLiteral) { - address = replacement.number.toUInt() + if(node===target && replacement is Expression) { + target = replacement } else throw FatalAstException("can't replace $node") } - override fun copy() = Jump(address, identifier?.copy(), position) + override fun copy() = Jump(target.copy(), position) override fun accept(visitor: IAstVisitor) = visitor.visit(this) override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - override fun referencesIdentifier(nameInSource: List): Boolean = identifier?.referencesIdentifier(nameInSource)==true + override fun referencesIdentifier(nameInSource: List): Boolean = target.referencesIdentifier(nameInSource) override fun toString() = - "Jump(addr: $address, identifier: $identifier, pos=$position)" + "Jump($target, pos=$position)" } class FunctionCallStatement(override var target: IdentifierReference, diff --git a/compilerAst/src/prog8/ast/walk/AstWalker.kt b/compilerAst/src/prog8/ast/walk/AstWalker.kt index 7044cb67b..c30bf2884 100644 --- a/compilerAst/src/prog8/ast/walk/AstWalker.kt +++ b/compilerAst/src/prog8/ast/walk/AstWalker.kt @@ -299,7 +299,7 @@ abstract class AstWalker { fun visit(jump: Jump, parent: Node) { track(before(jump, parent), jump, parent) - jump.identifier?.accept(this, jump) + jump.target.accept(this, jump) track(after(jump, parent), jump, parent) } diff --git a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt index 566a6daa8..c1f0609d7 100644 --- a/compilerAst/src/prog8/ast/walk/IAstVisitor.kt +++ b/compilerAst/src/prog8/ast/walk/IAstVisitor.kt @@ -63,7 +63,7 @@ interface IAstVisitor { } fun visit(jump: Jump) { - jump.identifier?.accept(this) + jump.target.accept(this) } fun visit(ifElse: IfElse) { diff --git a/compilerAst/src/prog8/compiler/CallGraph.kt b/compilerAst/src/prog8/compiler/CallGraph.kt index 9abb45f24..e3a06e0de 100644 --- a/compilerAst/src/prog8/compiler/CallGraph.kt +++ b/compilerAst/src/prog8/compiler/CallGraph.kt @@ -95,7 +95,7 @@ class CallGraph(private val program: Program) : IAstVisitor { } override fun visit(jump: Jump) { - val otherSub = jump.identifier?.targetSubroutine(program) + val otherSub = (jump.target as? IdentifierReference)?.targetSubroutine(program) if (otherSub != null) { jump.definingSubroutine?.let { thisSub -> calls[thisSub] = calls.getValue(thisSub) + otherSub diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 8ebd970cc..d7be220e8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,12 +1,16 @@ TODO ==== +goto can now accept any expression (instead of just a constant address or an identifier). +document this. + FIX code gen for the case where the target is a non-constant expression! See TODOs with "GOTO TARGET" + ... Future Things and Ideas ^^^^^^^^^^^^^^^^^^^^^^^ +- make word arrays split by default (remove @split tag) and use new @notsplit or @linear tag to make an array use the old storage format? Also remove -splitarrays command line option. Document this (also that word arrays can then have length 256 by default as well, and that @linear will reduce it to half.) - a syntax to access specific bits in a variable, to avoid manually shifts&ands, something like variable[4:8] ? (or something else this may be too similar to regular array indexing) - something to reduce the need to use fully qualified names all the time. 'with' ? Or 'using '? - Libraries: improve ability to create library files in prog8; for instance there's still stuff injected into the start of the start() routine AND there is separate setup logic going on before calling it. diff --git a/examples/test.p8 b/examples/test.p8 index b9dd41017..8aebdb732 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,29 +1,9 @@ -%import textio -%zeropage basicsafe -%option no_sysinit - main { sub start() { - regparams(true, 42, 9999) - } + goto $3000 + goto labeltje + goto cx16.r0+cx16.r1 - sub regparams(bool arg1 @R0, byte arg2 @R1, uword arg3 @R2) { - txt.print_bool(arg1) - txt.nl() - txt.print_b(arg2) - txt.nl() - txt.print_uw(arg3) - txt.nl() - - cx16.r0=0 - cx16.r1=$ffff - cx16.r2=11222 - - txt.print_bool(arg1) - txt.nl() - txt.print_b(arg2) - txt.nl() - txt.print_uw(arg3) - txt.nl() +labeltje: } } diff --git a/parser/src/main/antlr/Prog8ANTLR.g4 b/parser/src/main/antlr/Prog8ANTLR.g4 index dbebcab68..1b138ee89 100644 --- a/parser/src/main/antlr/Prog8ANTLR.g4 +++ b/parser/src/main/antlr/Prog8ANTLR.g4 @@ -147,7 +147,7 @@ defer: 'defer' (statement | statement_block) ; labeldef : identifier ':' ; -unconditionaljump : 'goto' (integerliteral | scoped_identifier) ; +unconditionaljump : 'goto' expression ; directive : directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%zpallowed' | '%address' | '%memtop' | '%import' |