mirror of
https://github.com/irmen/prog8.git
synced 2024-12-17 16:29:50 +00:00
fix symbol prefixing on goto with expression
added coroutines example
This commit is contained in:
parent
8ea032ed66
commit
7c79cdbd2f
@ -116,10 +116,9 @@ class PtIfElse(position: Position) : PtNode(position) {
|
||||
}
|
||||
|
||||
|
||||
class PtJump(val target: PtExpression, position: Position) : PtNode(position) {
|
||||
init {
|
||||
target.parent = this
|
||||
}
|
||||
class PtJump(position: Position) : PtNode(position) {
|
||||
val target: PtExpression
|
||||
get() = children.single() as PtExpression
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,16 +73,6 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
|
||||
nodesToPrefix += node.parent to index
|
||||
}
|
||||
}
|
||||
is PtJump -> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
is PtBlock -> prefixNamedNode(node)
|
||||
is PtConstant -> prefixNamedNode(node)
|
||||
is PtLabel -> prefixNamedNode(node)
|
||||
@ -107,7 +97,6 @@ class AsmGen6502(val prefixSymbols: Boolean, private val lastGeneratedLabelSeque
|
||||
when(val node = parent.children[index]) {
|
||||
is PtIdentifier -> parent.children[index] = node.prefix(parent, st)
|
||||
is PtFunctionCall -> throw AssemblyError("PtFunctionCall should be processed in their own list, last")
|
||||
is PtJump -> parent.children[index] = node.prefix(parent, st)
|
||||
is PtVariable -> parent.children[index] = node.prefix(parent, st)
|
||||
else -> throw AssemblyError("weird node to prefix $node")
|
||||
}
|
||||
@ -177,17 +166,6 @@ private fun PtVariable.prefix(parent: PtNode, st: SymbolTable): PtVariable {
|
||||
else this
|
||||
}
|
||||
|
||||
private fun PtJump.prefix(parent: PtNode, st: SymbolTable): PtJump {
|
||||
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 {
|
||||
val newName = prefixScopedName(name, 's')
|
||||
val call = PtFunctionCall(newName, void, type, position)
|
||||
|
@ -1660,6 +1660,7 @@ class IRCodeGen(
|
||||
IRInstruction(Opcode.JUMP, labelSymbol = identifier.name)
|
||||
}
|
||||
} else {
|
||||
// val tr = expressionEval.translateExpression(jump.target)
|
||||
TODO("JUMP to expression address ${jump.target}")
|
||||
}
|
||||
}
|
||||
|
@ -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(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), 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(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), 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(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) })
|
||||
if1.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also { it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), 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(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY), Position.DUMMY)) })
|
||||
if2.add(PtNodeGroup().also { it.add(PtJump(Position.DUMMY).also {it.add(PtNumber(BaseDataType.UWORD, 0xc000.toDouble(), Position.DUMMY)) }) })
|
||||
if2.add(PtNodeGroup())
|
||||
sub.add(if2)
|
||||
block.add(sub)
|
||||
|
@ -102,7 +102,7 @@ class Inliner(private val program: Program, private val options: CompilationOpti
|
||||
inline
|
||||
}
|
||||
|
||||
is Jump -> true
|
||||
is Jump -> stmt.target is NumericLiteral || stmt.target is IdentifierReference
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +378,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, srcIf.position))
|
||||
ifScope.add(PtJump(srcIf.position).also { it.add(elseLbl) })
|
||||
val elseScope = PtNodeGroup()
|
||||
branch.add(ifScope)
|
||||
branch.add(elseScope)
|
||||
@ -386,7 +386,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, srcIf.position))
|
||||
nodes.add(PtJump(srcIf.position).also { it.add(endLbl) })
|
||||
nodes.add(PtLabel(elseLabel, srcIf.position))
|
||||
if(srcIf.elsepart.isNotEmpty()) {
|
||||
for (stmt in srcIf.elsepart.statements)
|
||||
@ -451,7 +451,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
|
||||
private fun transform(srcJump: Jump): PtJump {
|
||||
val target = transformExpression(srcJump.target)
|
||||
return PtJump(target, srcJump.position)
|
||||
return PtJump(srcJump.position).also { it.add(target) }
|
||||
}
|
||||
|
||||
private fun transform(label: Label): PtLabel =
|
||||
|
@ -189,7 +189,9 @@ 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), Position.DUMMY))
|
||||
val jump = PtJump(Position.DUMMY)
|
||||
jump.add(PtIdentifier(defersRoutine.scopedName+"."+skiplabel, DataType.forDt(BaseDataType.UBYTE), Position.DUMMY))
|
||||
it.add(jump)
|
||||
})
|
||||
branchcc.add(PtNodeGroup())
|
||||
defersRoutine.add(branchcc)
|
||||
|
@ -171,6 +171,7 @@ class TestCompilerOnExamplesBothC64andCx16: FunSpec({
|
||||
listOf(
|
||||
"animals",
|
||||
"balls",
|
||||
"coroutines",
|
||||
"cube3d",
|
||||
"cube3d-float",
|
||||
"cube3d-gfx",
|
||||
|
@ -1,10 +1,6 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
- FIX: uword[] @nosplit tasklist = [&start-1] "initialisation value has incompatible type"
|
||||
- FIX: goto pointers[4]-1
|
||||
|
||||
|
||||
- DONE: make word arrays split by default and add new @nosplit tag to make an array use the old linear storage format
|
||||
- DONE: &splitarray will give you the start address of the lsb-array (which is immediately followed by the msb-array)
|
||||
- DONE: add &< and &> operators to get the address of the lsb-array and msb-array, respectively. (&< is just syntactic sugar for &)
|
||||
@ -58,7 +54,7 @@ IR/VM
|
||||
- fix call() return value handling
|
||||
- fix float register parameters (FAC1,FAC2) for extsubs, search for TODO("floating point register parameters not supported")
|
||||
- proper code gen for the CALLI instruction and that it (optionally) returns a word value that needs to be assigned to a reg
|
||||
- make it possible to jump and branch to a computed address (expression), see TODO("JUMP to expression address
|
||||
- make it possible to jump and branch to a computed address (expression), see TODO("JUMP to expression address" . This needs a change in the JUMPI instruction: it has to take a register instead (like CALLI)
|
||||
- idea: (but LLVM IR simply keeps the variables, so not a good idea then?...): replace all scalar variables by an allocated register. Keep a table of the variable to register mapping (including the datatype)
|
||||
global initialization values are simply a list of LOAD instructions.
|
||||
Variables replaced include all subroutine parameters! So the only variables that remain as variables are arrays and strings.
|
||||
|
128
examples/coroutines.p8
Normal file
128
examples/coroutines.p8
Normal file
@ -0,0 +1,128 @@
|
||||
|
||||
; Cooperative multitasking / Coroutines
|
||||
; Uses stack return address juggling to cycle between the different tasks when they call yield().
|
||||
|
||||
%import textio
|
||||
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
txt.print("cooperative multitasking / coroutines")
|
||||
coroutines.start()
|
||||
}
|
||||
}
|
||||
|
||||
coroutines {
|
||||
uword[] tasklist = [&task1, &task2, &task3, &task4, &vsynctask]
|
||||
|
||||
sub start() {
|
||||
goto tasklist[0]
|
||||
}
|
||||
|
||||
uword[len(tasklist)] returnaddresses
|
||||
ubyte active_task
|
||||
|
||||
sub yield() {
|
||||
; store the return address of the yielding task,
|
||||
; and continue with the next one instead (round-robin)
|
||||
returnaddresses[active_task] = sys.popw()
|
||||
active_task++
|
||||
if active_task==len(returnaddresses)
|
||||
active_task=0
|
||||
cx16.r0 = returnaddresses[active_task]
|
||||
if cx16.r0==0 {
|
||||
; fetch start address of next task.
|
||||
; address on the stack must be pushed in reverse byte order
|
||||
; also, subtract 1 from the start address because JSR pushes returnaddress minus 1
|
||||
cx16.r0 = tasklist[active_task]-1
|
||||
sys.push(cx16.r0H)
|
||||
sys.push(cx16.r0L)
|
||||
} else
|
||||
sys.pushw(cx16.r0)
|
||||
|
||||
; returning from yield then continues with the next coroutine
|
||||
}
|
||||
|
||||
sub task1() {
|
||||
const ubyte x = 5
|
||||
ubyte y
|
||||
repeat {
|
||||
for y in 10 to 24 {
|
||||
txt.setchr(x, y-1, sc:' ')
|
||||
txt.setchr(x, y, sc:'1')
|
||||
yield()
|
||||
}
|
||||
for y in 24 downto 10 {
|
||||
txt.setchr(x, y+1, sc:' ')
|
||||
txt.setchr(x, y, sc:'1')
|
||||
yield()
|
||||
}
|
||||
}
|
||||
; need infinite loop
|
||||
}
|
||||
|
||||
sub task2() {
|
||||
const ubyte x = 10
|
||||
ubyte y
|
||||
repeat {
|
||||
for y in 5 to 18 {
|
||||
txt.setchr(x, y-1, sc:' ')
|
||||
txt.setchr(x, y, sc:'2')
|
||||
yield()
|
||||
}
|
||||
for y in 18 downto 5 {
|
||||
txt.setchr(x, y+1, sc:' ')
|
||||
txt.setchr(x, y, sc:'2')
|
||||
yield()
|
||||
}
|
||||
}
|
||||
; need infinite loop
|
||||
}
|
||||
|
||||
sub task3() {
|
||||
ubyte x
|
||||
const ubyte y = 10
|
||||
repeat {
|
||||
for x in 14 to 38 {
|
||||
txt.setchr(x-1, y, sc:' ')
|
||||
txt.setchr(x, y, sc:'3')
|
||||
yield()
|
||||
}
|
||||
for x in 38 downto 14 {
|
||||
txt.setchr(x+1, y, sc:' ')
|
||||
txt.setchr(x, y, sc:'3')
|
||||
yield()
|
||||
}
|
||||
}
|
||||
; need infinite loop
|
||||
}
|
||||
|
||||
sub task4() {
|
||||
ubyte x
|
||||
const ubyte y = 14
|
||||
repeat {
|
||||
for x in 15 to 30 {
|
||||
txt.setchr(x-1, y, sc:' ')
|
||||
txt.setchr(x, y, sc:'4')
|
||||
yield()
|
||||
}
|
||||
for x in 30 downto 15 {
|
||||
txt.setchr(x+1, y, sc:' ')
|
||||
txt.setchr(x, y, sc:'4')
|
||||
yield()
|
||||
}
|
||||
}
|
||||
; need infinite loop
|
||||
}
|
||||
|
||||
sub vsynctask() {
|
||||
repeat {
|
||||
sys.waitvsync()
|
||||
sys.waitvsync()
|
||||
yield()
|
||||
}
|
||||
; need infinite loop
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
main {
|
||||
sub start() {
|
||||
uword[] @nosplit tasklist = [&start-1]
|
||||
; uword task_address = tasklist[0]
|
||||
; goto task_address
|
||||
uword[] tasklist = [1111,2222,3333]
|
||||
uword task_address = tasklist[0]
|
||||
goto task_address
|
||||
goto task_address+1
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user