mirror of
https://github.com/irmen/prog8.git
synced 2024-12-23 09:32:43 +00:00
continue stmt added
This commit is contained in:
parent
9ef9c24388
commit
c45fbe6310
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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())
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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)* ;
|
||||
|
@ -11,7 +11,7 @@
|
||||
<option name="HAS_PARENS" value="true" />
|
||||
<option name="HAS_STRING_ESCAPES" value="true" />
|
||||
</options>
|
||||
<keywords keywords="&;->;@;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="&;->;@;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;|>" />
|
||||
|
@ -26,7 +26,7 @@
|
||||
<Keywords name="Folders in comment, close"></Keywords>
|
||||
<Keywords name="Keywords1">void const
str
byte ubyte bool
word uword
float
zp shared split requirezp</Keywords>
|
||||
<Keywords name="Keywords2">%address
%asm
%ir
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved
%zpallowed</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
break return goto</Keywords>
|
||||
<Keywords name="Keywords3">inline sub asmsub romsub
clobbers
asm
if
when else
if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z
for in step do while repeat unroll
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
not and or xor
as to downto |></Keywords>
|
||||
<Keywords name="Keywords6"></Keywords>
|
||||
|
@ -37,6 +37,7 @@ main {
|
||||
when ch {
|
||||
0 -> {
|
||||
break
|
||||
continue
|
||||
}
|
||||
else -> {
|
||||
temp[0] = ch
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user