continue stmt added

This commit is contained in:
Irmen de Jong 2023-11-19 17:52:43 +01:00
parent 9ef9c24388
commit c45fbe6310
15 changed files with 141 additions and 50 deletions

View File

@ -5,11 +5,11 @@ package prog8.buildversion
*/
const val MAVEN_GROUP = "prog8"
const val MAVEN_NAME = "compiler"
const val VERSION = "9.6-SNAPSHOT"
const val GIT_REVISION = 4159
const val GIT_SHA = "335213b55f971452a05c904216cb0fd72f5518a1"
const val GIT_DATE = "2023-10-21T00:16:58Z"
const val GIT_BRANCH = "master"
const val BUILD_DATE = "2023-10-21T20:22:14Z"
const val BUILD_UNIX_TIME = 1697919734197L
const val VERSION = "9.7-SNAPSHOT"
const val GIT_REVISION = 4212
const val GIT_SHA = "f81061dd42403294e7cb5ebd3c0ed57d6c57c3d5"
const val GIT_DATE = "2023-11-18T00:03:34Z"
const val GIT_BRANCH = "continue-stmt"
const val BUILD_DATE = "2023-11-19T16:19:02Z"
const val BUILD_UNIX_TIME = 1700410742198L
const val DIRTY = 1

View File

@ -19,7 +19,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
// have been performed (because those could re-introduce nodes that have to be desugared)
//
// List of modifications:
// - replace 'break' statements by a goto + generated after label.
// - replace 'break' and 'continue' statements by a goto + generated after label.
// - replace while and do-until loops by just jumps.
// - replace peek() and poke() by direct memory accesses.
// - repeat-forever loops replaced by label+jump.
@ -52,6 +52,39 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
}
}
override fun before(continueStmt: Continue, parent: Node): Iterable<IAstModification> {
fun jumpToBottom(scope: IStatementContainer): Iterable<IAstModification> {
val label = program.makeLabel("cont", continueStmt.position)
return listOf(
IAstModification.ReplaceNode(continueStmt, program.jumpLabel(label), parent),
IAstModification.InsertLast(label, scope)
)
}
fun jumpToBefore(loop: WhileLoop): Iterable<IAstModification> {
val label = program.makeLabel("cont", continueStmt.position)
return listOf(
IAstModification.ReplaceNode(continueStmt, program.jumpLabel(label), parent),
IAstModification.InsertBefore(loop, label, loop.parent as IStatementContainer)
)
}
var partof = parent
while(true) {
when (partof) {
is Subroutine, is Block, is ParentSentinel -> {
errors.err("continue in wrong scope", continueStmt.position)
return noModifications
}
is ForLoop -> return jumpToBottom(partof.body)
is RepeatLoop -> return jumpToBottom(partof.body)
is UntilLoop -> return jumpToBottom(partof.body)
is WhileLoop -> return jumpToBefore(partof)
else -> partof = partof.parent
}
}
}
override fun after(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> {
/*
do { STUFF } until CONDITION

View File

@ -40,6 +40,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
is Assignment -> transform(statement)
is Block -> transform(statement)
is Break -> throw FatalAstException("break should have been replaced by Goto")
is Continue -> throw FatalAstException("continue should have been replaced by Goto")
is BuiltinFunctionCallStatement -> transform(statement)
is BuiltinFunctionPlaceholder -> throw FatalAstException("BuiltinFunctionPlaceholder should not occur in Ast here")
is ConditionalBranch -> transform(statement)

View File

@ -7,7 +7,6 @@ import prog8.ast.base.SyntaxError
import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.code.core.*
import prog8.parser.Prog8ANTLRParser
import prog8.parser.Prog8ANTLRParser.*
import kotlin.io.path.Path
import kotlin.io.path.isRegularFile
@ -145,11 +144,14 @@ private fun StatementContext.toAst() : Statement {
val repeatloop = repeatloop()?.toAst()
if(repeatloop!=null) return repeatloop
val whenstmt = whenstmt()?.toAst()
if(whenstmt!=null) return whenstmt
val breakstmt = breakstmt()?.toAst()
if(breakstmt!=null) return breakstmt
val whenstmt = whenstmt()?.toAst()
if(whenstmt!=null) return whenstmt
val continuestmt = continuestmt()?.toAst()
if(continuestmt!=null) return continuestmt
val unrollstmt = unrollloop()?.toAst()
if(unrollstmt!=null) return unrollstmt
@ -573,6 +575,8 @@ private fun ForloopContext.toAst(): ForLoop {
private fun BreakstmtContext.toAst() = Break(toPosition())
private fun ContinuestmtContext.toAst() = Continue(toPosition())
private fun WhileloopContext.toAst(): WhileLoop {
val condition = expression().toAst()
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())

View File

@ -173,6 +173,20 @@ class Break(override val position: Position) : Statement() {
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
}
class Continue(override val position: Position) : Statement() {
override lateinit var parent: Node
override fun linkParents(parent: Node) {
this.parent=parent
}
override fun replaceChildNode(node: Node, replacement: Node) = throw FatalAstException("can't replace here")
override fun referencesIdentifier(nameInSource: List<String>): Boolean = false
override fun copy() = Break(position)
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
}
enum class VarDeclOrigin {
USERCODE,

View File

@ -99,6 +99,7 @@ abstract class AstWalker {
open fun before(block: Block, parent: Node): Iterable<IAstModification> = noModifications
open fun before(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> = noModifications
open fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> = noModifications
open fun before(continueStmt: Continue, parent: Node): Iterable<IAstModification> = noModifications
open fun before(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
open fun before(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun before(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications
@ -142,6 +143,7 @@ abstract class AstWalker {
open fun after(block: Block, parent: Node): Iterable<IAstModification> = noModifications
open fun after(branch: ConditionalBranch, parent: Node): Iterable<IAstModification> = noModifications
open fun after(breakStmt: Break, parent: Node): Iterable<IAstModification> = noModifications
open fun after(continueStmt: Continue, parent: Node): Iterable<IAstModification> = noModifications
open fun after(containment: ContainmentCheck, parent: Node): Iterable<IAstModification> = noModifications
open fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> = noModifications
open fun after(directive: Directive, parent: Node): Iterable<IAstModification> = noModifications
@ -374,6 +376,11 @@ abstract class AstWalker {
track(after(breakStmt, parent), breakStmt, parent)
}
fun visit(continueStmt: Continue, parent: Node) {
track(before(continueStmt, parent), continueStmt, parent)
track(after(continueStmt, parent), continueStmt, parent)
}
fun visit(forLoop: ForLoop, parent: Node) {
track(before(forLoop, parent), forLoop, parent)
forLoop.loopVar.accept(this, forLoop)

View File

@ -115,6 +115,9 @@ interface IAstVisitor {
fun visit(breakStmt: Break) {
}
fun visit(continueStmt: Continue) {
}
fun visit(forLoop: ForLoop) {
forLoop.loopVar.accept(this)
forLoop.iterable.accept(this)

View File

@ -501,7 +501,9 @@ The *repeat* loop is used as a short notation of a for loop where the loop varia
You can also create loops by using the ``goto`` statement, but this should usually be avoided.
Breaking out of a loop prematurely is possible with the ``break`` statement.
Breaking out of a loop prematurely is possible with the ``break`` statement,
immediately continue into the next cycle of the loop with the ``continue`` statement.
(These are just shorthands for a goto + a label)
The *unroll* loop is not really a loop, but looks like one. It actually duplicates the statements in its block on the spot by
the given number of times. It's meant to "unroll loops" - trade memory for speed by avoiding the actual repeat loop counting code.

View File

@ -745,6 +745,7 @@ You can use a single statement, or a statement block like in the example below::
for <loopvar> in <expression> [ step <amount> ] {
; do something...
break ; break out of the loop
continue ; immediately next iteration
}
For example, this is a for loop using a byte variable ``i``, defined before, to loop over a certain range of numbers::
@ -778,6 +779,7 @@ You can use a single statement, or a statement block like in the example below::
while <condition> {
; do something...
break ; break out of the loop
continue ; immediately next iteration
}
@ -790,6 +792,7 @@ You can use a single statement, or a statement block like in the example below::
do {
; do something...
break ; break out of the loop
continue ; immediately next iteration
} until <condition>
@ -802,6 +805,7 @@ It's a short hand for a for loop without an explicit loop variable::
repeat 15 {
; do something...
break ; you can break out of the loop
continue ; immediately next iteration
}
If you omit the iteration count, it simply loops forever.
@ -820,7 +824,7 @@ Also, only simple statements such as assignments and function calls can be insid
cx16.VERA_DATA0 = 255
}
A `break` statement cannot occur in an unroll loop, as there is not really a loop to break out of.
A `break` or `continue` statement cannot occur in an unroll loop, as there is no actual loop to break out of.
Conditional Execution and Jumps

View File

@ -1,43 +1,62 @@
%import textio
%import bmx
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
str filename = "?"*40
repeat {
txt.print("\nenter bmx image filename: ")
if txt.input_chars(&filename) {
if bmx.load_header(8, filename) {
txt.print("\nwidth: ")
txt.print_uw(bmx.width)
txt.print("\nheight: ")
txt.print_uw(bmx.height)
txt.print("\nbpp: ")
txt.print_uw(bmx.bitsperpixel)
txt.nl()
sys.wait(100)
; switch to correct screen mode and color depth
void cx16.screen_mode($80, false)
cx16.VERA_L0_CONFIG = cx16.VERA_L0_CONFIG & %11111100 | bmx.vera_colordepth
; actually load
if bmx.load(8, filename, 0, 0, 320) {
void txt.waitkey()
}
}
cbm.CINT() ; reset screen
if bmx.error_message {
txt.print("load error:\n")
txt.print(bmx.error_message)
txt.nl()
sys.wait(120)
}
}
txt.print("for:\n")
for cx16.r0L in 10 to 20 {
txt.print_ub(cx16.r0L)
txt.print(" before...")
if cx16.r0L > 15
break
if cx16.r0L ==14
continue
txt.print("after\n")
}
txt.nl()
txt.print("repeat:\n")
cx16.r0L=10
repeat 10 {
cx16.r0L++
txt.print_ub(cx16.r0L)
txt.print(" before...")
if cx16.r0L > 15
break
if cx16.r0L ==14
continue
txt.print("after\n")
}
txt.nl()
txt.print("while:\n")
cx16.r0L=10
while cx16.r0L<20 {
cx16.r0L++
txt.print_ub(cx16.r0L)
txt.print(" before...")
if cx16.r0L > 15
break
if cx16.r0L ==14
continue
txt.print("after\n")
}
txt.nl()
txt.print("until:\n")
cx16.r0L=10
do {
cx16.r0L++
txt.print_ub(cx16.r0L)
txt.print(" before...")
if cx16.r0L > 15
break
if cx16.r0L ==14
continue
txt.print("after\n")
} until cx16.r0L>20
txt.nl()
}
}

View File

@ -100,6 +100,7 @@ statement :
| unrollloop
| whenstmt
| breakstmt
| continuestmt
| labeldef
;
@ -210,6 +211,8 @@ returnstmt : 'return' expression? ;
breakstmt : 'break';
continuestmt: 'continue';
identifier : NAME ;
scoped_identifier : NAME ('.' NAME)* ;

View File

@ -11,7 +11,7 @@
<option name="HAS_PARENS" value="true" />
<option name="HAS_STRING_ESCAPES" value="true" />
</options>
<keywords keywords="&amp;;-&gt;;@;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
<keywords keywords="&amp;;-&gt;;@;and;as;asmsub;break;clobbers;continue;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;unroll;until;when;while;xor;~" ignore_case="false" />
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%ir;%launcher;%option;%output;%zeropage;%zpallowed;%zpreserved;iso:;petscii:;sc:" />
<keywords3 keywords="@requirezp;@shared;@split;@zp;bool;byte;const;float;str;ubyte;uword;void;word" />
<keywords4 keywords="abs;all;any;callfar;callram;callrom;clamp;cmp;divmod;len;lsb;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;reverse;rol;rol2;ror;ror2;rrestore;rrestorex;rsave;rsavex;setlsb;setmsb;sgn;sizeof;sort;sqrt;swap;|&gt;" />

View File

@ -26,7 +26,7 @@
<Keywords name="Folders in comment, close"></Keywords>
<Keywords name="Keywords1">void const&#x000D;&#x000A;str&#x000D;&#x000A;byte ubyte bool&#x000D;&#x000A;word uword&#x000D;&#x000A;float&#x000D;&#x000A;zp shared split requirezp</Keywords>
<Keywords name="Keywords2">%address&#x000D;&#x000A;%asm&#x000D;&#x000A;%ir&#x000D;&#x000A;%asmbinary&#x000D;&#x000A;%asminclude&#x000D;&#x000A;%breakpoint&#x000D;&#x000A;%import&#x000D;&#x000A;%launcher&#x000D;&#x000A;%option&#x000D;&#x000A;%output&#x000D;&#x000A;%zeropage&#x000D;&#x000A;%zpreserved&#x000D;&#x000A;%zpallowed</Keywords>
<Keywords name="Keywords3">inline sub asmsub romsub&#x000D;&#x000A;clobbers&#x000D;&#x000A;asm&#x000D;&#x000A;if&#x000D;&#x000A;when else&#x000D;&#x000A;if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z&#x000D;&#x000A;for in step do while repeat unroll&#x000D;&#x000A;break return goto</Keywords>
<Keywords name="Keywords3">inline sub asmsub romsub&#x000D;&#x000A;clobbers&#x000D;&#x000A;asm&#x000D;&#x000A;if&#x000D;&#x000A;when else&#x000D;&#x000A;if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z&#x000D;&#x000A;for in step do while repeat unroll&#x000D;&#x000A;break continue return goto</Keywords>
<Keywords name="Keywords4">abs all any callfar clamp cmp divmod len lsb lsl lsr memory mkword min max msb peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex reverse rnd rndw rol rol2 ror ror2 setlsb setmsb sgn sizeof sort sqrtw swap</Keywords>
<Keywords name="Keywords5">true false&#x000D;&#x000A;not and or xor&#x000D;&#x000A;as to downto |&gt;</Keywords>
<Keywords name="Keywords6"></Keywords>

View File

@ -37,6 +37,7 @@ main {
when ch {
0 -> {
break
continue
}
else -> {
temp[0] = ch

View File

@ -23,7 +23,7 @@ syn region prog8Expression matchgroup=prog8AddressOp start="@(" end=")"
syn match prog8Function "\(\<\(asm\)\?sub\>\s\+\)\@16<=\<\w\+\>"
syn match prog8Function "\(romsub\s\+$\x\+\s\+=\s\+\)\@16<=\<\w\+\>"
syn keyword prog8Statement break goto return asmsub sub inline
syn keyword prog8Statement break continue goto return asmsub sub inline
syn match prog8Statement "\<\(asm\|rom\)\?sub\>"
syn keyword prog8Conditional if else when
syn keyword prog8Conditional if_cs if_cc if_vs if_vc if_eq if_z if_ne if_nz