mirror of
https://github.com/irmen/prog8.git
synced 2025-03-06 05:29:45 +00:00
allow goto to take any expression, not only an integer or an identifier (part 1)
This commit is contained in:
parent
697d54e10a
commit
cc59069876
@ -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(", ") {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<String, Boolean> {
|
||||
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) {
|
||||
|
@ -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 <place> (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<IRCodeChunkBase>()
|
||||
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<IRCodeChunkBase>()
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -91,8 +91,9 @@ private fun integrateDefers(subdefers: Map<PtSub, List<PtDefer>>, 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<PtSub, List<PtDefer>>, 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)
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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<String>): Boolean = identifier?.referencesIdentifier(nameInSource)==true
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean = target.referencesIdentifier(nameInSource)
|
||||
|
||||
override fun toString() =
|
||||
"Jump(addr: $address, identifier: $identifier, pos=$position)"
|
||||
"Jump($target, pos=$position)"
|
||||
}
|
||||
|
||||
class FunctionCallStatement(override var target: IdentifierReference,
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ interface IAstVisitor {
|
||||
}
|
||||
|
||||
fun visit(jump: Jump) {
|
||||
jump.identifier?.accept(this)
|
||||
jump.target.accept(this)
|
||||
}
|
||||
|
||||
fun visit(ifElse: IfElse) {
|
||||
|
@ -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
|
||||
|
@ -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 <prefix>'?
|
||||
- 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.
|
||||
|
@ -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:
|
||||
}
|
||||
}
|
||||
|
@ -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' |
|
||||
|
Loading…
x
Reference in New Issue
Block a user