diff --git a/compiler/antlr/prog8.g4 b/compiler/antlr/prog8.g4 index 6944fb99f..7046249c0 100644 --- a/compiler/antlr/prog8.g4 +++ b/compiler/antlr/prog8.g4 @@ -253,7 +253,7 @@ branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ; -forloop : 'for' (register | identifier) 'in' expression EOL? statement_block ; +forloop : 'for' datatype? (register | identifier) 'in' expression EOL? statement_block ; whileloop: 'while' expression EOL? (statement | statement_block) ; diff --git a/compiler/examples/cube3d.p8 b/compiler/examples/cube3d.p8 index 2f40851b0..dbcbad313 100644 --- a/compiler/examples/cube3d.p8 +++ b/compiler/examples/cube3d.p8 @@ -69,8 +69,7 @@ float Azy = cosb*sinc float Azz = cosb*cosc - byte i - for i in 0 to len(xcoor)-1 { + for byte i in 0 to len(xcoor)-1 { rotatedx[i] = Axx*xcoor[i] + Axy*ycoor[i] + Axz*zcoor[i] rotatedy[i] = Ayx*xcoor[i] + Ayy*ycoor[i] + Ayz*zcoor[i] rotatedz[i] = Azx*xcoor[i] + Azy*ycoor[i] + Azz*zcoor[i] @@ -89,8 +88,7 @@ } ; draw all edges of the object - word edge - for edge in edges { + for word edge in edges { byte e_from = msb(edge) byte e_to = lsb(edge) _vm_gfx_line(toscreenx(rotatedx[e_from], rotatedz[e_from]), toscreeny(rotatedy[e_from], rotatedz[e_from]), @@ -98,8 +96,7 @@ } ; accentuate the vertices a bit with small boxes - byte i - for i in 0 to len(xcoor)-1 { + for byte i in 0 to len(xcoor)-1 { word sx = toscreenx(rotatedx[i], rotatedz[i]) word sy = toscreeny(rotatedy[i], rotatedz[i]) byte color=i+2 diff --git a/compiler/examples/mandelbrot.p8 b/compiler/examples/mandelbrot.p8 index d9e607d14..124d33f02 100644 --- a/compiler/examples/mandelbrot.p8 +++ b/compiler/examples/mandelbrot.p8 @@ -10,12 +10,10 @@ _vm_gfx_clearscr(11) _vm_gfx_text(2, 1, 1, "Calculating Mandelbrot Fractal...") - byte pixely ; @todo allow defining loopvar INSIDE loop scope ("for byte pixely in ...") - for pixely in yoffset to yoffset+height-1 { + for byte pixely in yoffset to yoffset+height-1 { float yy = flt((pixely-yoffset))/height/3.6+0.4 - word pixelx ; @todo allow defining loopvar INSIDE loop scope ("for word pixelx in ...") - for pixelx in xoffset to xoffset+width-1 { + for word pixelx in xoffset to xoffset+width-1 { float xx = flt((pixelx-xoffset))/width/3.0+0.2 float xsquared float ysquared diff --git a/compiler/examples/numbergame.p8 b/compiler/examples/numbergame.p8 index e8362aa08..28af6d32b 100644 --- a/compiler/examples/numbergame.p8 +++ b/compiler/examples/numbergame.p8 @@ -11,8 +11,7 @@ _vm_write_str(name) _vm_write_str(".\nI am thinking of a number from 1 to 100! You'll have to guess it!\n") - byte attempts_left - for attempts_left in 10 to 1 step -1 { + for byte attempts_left in 10 to 1 step -1 { _vm_write_str("\nYou have ") _vm_write_num(attempts_left) _vm_write_str(" guess") diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index c9d989b36..9febb5536 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -5,44 +5,14 @@ ~ main { sub start() { - byte x - for x in 0 to 20 { - float xx = sin(flt(x)) - float yy = cos(flt(x)) + ; word [20] prime_numbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71] ; todo array_w!!! + word [20] fibonacci_numbers = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181] + + for word fibnr in fibonacci_numbers { + _vm_write_num(fibnr) + _vm_write_char('\n') } - - while(1) { - float xx = sin(flt(x)) - float yy = cos(flt(x)) - } - - repeat { - float xx = sin(flt(x)) - float yy = cos(flt(x)) - } until(1) - - - - - -; for x in 0 to 30 { -; float xx = 2123.33 -; float yy = 2444.55 -; xx = sin(flt(x)) -; yy = cos(flt(x)) -; r = xx*yy -; } -; -; for x in 0 to 40 { -; float xx = 3123.33 -; float yy = 3444.55 -; xx = sin(flt(x)) -; yy = cos(flt(x)) -; r = xx*yy -; } - return - } } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 3ca487546..4deb82284 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -367,12 +367,6 @@ interface INameScope { printNames(0, this) } - fun removeStatement(statement: IStatement) { - // remove a statement (most likely because it is never referenced such as a subroutine) - val removed = statements.remove(statement) - if(!removed) throw AstException("node to remove wasn't found") - } - fun isEmpty() = statements.isEmpty() } @@ -1371,6 +1365,7 @@ class BranchStatement(var condition: BranchCondition, class ForLoop(val loopRegister: Register?, + val decltype: DataType?, val loopVar: IdentifierReference?, var iterable: IExpression, var body: AnonymousScope, @@ -1379,7 +1374,7 @@ class ForLoop(val loopRegister: Register?, override fun linkParents(parent: Node) { this.parent=parent - loopVar?.linkParents(this) + loopVar?.linkParents(if(decltype==null) this else body) iterable.linkParents(this) body.linkParents(this) } @@ -1856,10 +1851,11 @@ private fun prog8Parser.BranchconditionContext.toAst() = BranchCondition.valueOf private fun prog8Parser.ForloopContext.toAst(): ForLoop { val loopregister = register()?.toAst() + val datatype = datatype()?.toAst() val loopvar = identifier()?.toAst() val iterable = expression()!!.toAst() val scope = AnonymousScope(statement_block().toAst(), statement_block().toPosition()) - return ForLoop(loopregister, loopvar, iterable, scope, toPosition()) + return ForLoop(loopregister, datatype, loopvar, iterable, scope, toPosition()) } diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index d7cff9e9b..320954591 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -115,4 +115,29 @@ class AstIdentifiersChecker : IAstProcessor { } return super.process(label) } + + override fun process(forLoop: ForLoop): IStatement { + // if the for loop as a decltype, it means to declare the loopvar inside the loop body + // rather than reusing an already declared loopvar from an outer scope. + if(forLoop.loopRegister!=null && forLoop.decltype!=null) { + checkResult.add(SyntaxError("register loop variables cannot be explicitly declared with a datatype", forLoop.position)) + } else { + val loopVar = forLoop.loopVar!! + val varName = loopVar.nameInSource.last() + when (forLoop.decltype) { + DataType.BYTE, DataType.WORD -> { + val existing = if(forLoop.body.isEmpty()) null else forLoop.body.lookup(loopVar.nameInSource, forLoop.body.statements.first()) + if(existing==null) { + val vardecl = VarDecl(VarDeclType.VAR, forLoop.decltype, null, varName, null, loopVar.position) + vardecl.linkParents(forLoop.body) + forLoop.body.statements.add(0, vardecl) + forLoop.loopVar.parent = forLoop.body // loopvar 'is defined in the body' + } + } + null -> {} + else -> checkResult.add(SyntaxError("loop variables can only be a byte or word", forLoop.position)) + } + } + return super.process(forLoop) + } } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 5a3fdd7ae..0c4af30f3 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -1198,6 +1198,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, } DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt") + null -> throw CompilerException("could not determine targetdt") // todo: maybe if you assign byte or word to array/matrix, clear it with that value? } } @@ -1474,10 +1475,10 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, val assignTarget = if(loop.loopRegister!=null) AssignTarget(loop.loopRegister, null, null, loop.position) else - AssignTarget(null, loop.loopVar, null, loop.position) + AssignTarget(null, loop.loopVar!!.copy(), null, loop.position) val arrayspec = ArraySpec(RegisterExpr(Register.valueOf(indexVar), loop.position), null, loop.position) - val assignLv = Assignment(assignTarget, null, ArrayIndexedExpression(loop.iterable as IdentifierReference, null, arrayspec, loop.position), loop.position) - assignLv.linkParents(loop.parent) + val assignLv = Assignment(assignTarget, null, ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), null, arrayspec, loop.position), loop.position) + assignLv.linkParents(loop.body) translate(assignLv) translate(loop.body) stackvmProg.label(continueLabel) diff --git a/compiler/src/prog8/parser/prog8Lexer.java b/compiler/src/prog8/parser/prog8Lexer.java index e91c2ec5d..2df8649ff 100644 --- a/compiler/src/prog8/parser/prog8Lexer.java +++ b/compiler/src/prog8/parser/prog8Lexer.java @@ -1,12 +1,13 @@ // Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7 package prog8.parser; - +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.LexerATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class prog8Lexer extends Lexer { diff --git a/compiler/src/prog8/parser/prog8Parser.java b/compiler/src/prog8/parser/prog8Parser.java index c93e82623..eb0b833ef 100644 --- a/compiler/src/prog8/parser/prog8Parser.java +++ b/compiler/src/prog8/parser/prog8Parser.java @@ -1,15 +1,13 @@ // Generated from /home/irmen/Projects/prog8/compiler/antlr/prog8.g4 by ANTLR 4.7 package prog8.parser; - -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNDeserializer; -import org.antlr.v4.runtime.atn.ParserATNSimulator; -import org.antlr.v4.runtime.atn.PredictionContextCache; +import org.antlr.v4.runtime.atn.*; import org.antlr.v4.runtime.dfa.DFA; -import org.antlr.v4.runtime.tree.TerminalNode; - +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; import java.util.List; +import java.util.Iterator; +import java.util.ArrayList; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class prog8Parser extends Parser { @@ -3897,6 +3895,9 @@ public class prog8Parser extends Parser { public IdentifierContext identifier() { return getRuleContext(IdentifierContext.class,0); } + public DatatypeContext datatype() { + return getRuleContext(DatatypeContext.class,0); + } public TerminalNode EOL() { return getToken(prog8Parser.EOL, 0); } public ForloopContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -3913,7 +3914,17 @@ public class prog8Parser extends Parser { { setState(571); match(T__99); - setState(574); + setState(573); + _errHandler.sync(this); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__16) | (1L << T__17) | (1L << T__18) | (1L << T__19) | (1L << T__20) | (1L << T__21) | (1L << T__22))) != 0)) { + { + setState(572); + datatype(); + } + } + + setState(577); _errHandler.sync(this); switch (_input.LA(1)) { case T__64: @@ -3923,34 +3934,34 @@ public class prog8Parser extends Parser { case T__68: case T__69: { - setState(572); + setState(575); register(); } break; case NAME: { - setState(573); + setState(576); identifier(); } break; default: throw new NoViableAltException(this); } - setState(576); - match(T__100); - setState(577); - expression(0); setState(579); + match(T__100); + setState(580); + expression(0); + setState(582); _errHandler.sync(this); _la = _input.LA(1); if (_la==EOL) { { - setState(578); + setState(581); match(EOL); } } - setState(581); + setState(584); statement_block(); } } @@ -3989,21 +4000,21 @@ public class prog8Parser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(583); - match(T__101); - setState(584); - expression(0); setState(586); + match(T__101); + setState(587); + expression(0); + setState(589); _errHandler.sync(this); _la = _input.LA(1); if (_la==EOL) { { - setState(585); + setState(588); match(EOL); } } - setState(590); + setState(593); _errHandler.sync(this); switch (_input.LA(1)) { case T__2: @@ -4055,13 +4066,13 @@ public class prog8Parser extends Parser { case T__102: case NAME: { - setState(588); + setState(591); statement(); } break; case T__80: { - setState(589); + setState(592); statement_block(); } break; @@ -4105,9 +4116,9 @@ public class prog8Parser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(592); - match(T__102); setState(595); + match(T__102); + setState(598); _errHandler.sync(this); switch (_input.LA(1)) { case T__2: @@ -4159,32 +4170,32 @@ public class prog8Parser extends Parser { case T__102: case NAME: { - setState(593); + setState(596); statement(); } break; case T__80: { - setState(594); + setState(597); statement_block(); } break; default: throw new NoViableAltException(this); } - setState(598); + setState(601); _errHandler.sync(this); _la = _input.LA(1); if (_la==EOL) { { - setState(597); + setState(600); match(EOL); } } - setState(600); + setState(603); match(T__103); - setState(601); + setState(604); expression(0); } } @@ -4237,7 +4248,7 @@ public class prog8Parser extends Parser { } public static final String _serializedATN = - "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3v\u025e\4\2\t\2\4"+ + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3v\u0261\4\2\t\2\4"+ "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ @@ -4278,53 +4289,53 @@ public class prog8Parser extends Parser { "\n\65\3\66\3\66\3\66\5\66\u0216\n\66\3\66\3\66\5\66\u021a\n\66\3\66\5"+ "\66\u021d\n\66\3\66\5\66\u0220\n\66\3\66\3\66\3\67\3\67\5\67\u0226\n\67"+ "\3\67\3\67\5\67\u022a\n\67\38\38\58\u022e\n8\38\38\58\u0232\n8\38\58\u0235"+ - "\n8\38\58\u0238\n8\38\38\39\39\3:\3:\3:\5:\u0241\n:\3:\3:\3:\5:\u0246"+ - "\n:\3:\3:\3;\3;\3;\5;\u024d\n;\3;\3;\5;\u0251\n;\3<\3<\3<\5<\u0256\n<"+ - "\3<\5<\u0259\n<\3<\3<\3<\3<\2\3&=\2\4\6\b\n\f\16\20\22\24\26\30\32\34"+ - "\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNPRTVXZ\\^`bdfhjlnprtv\2\20\3\2\6\16"+ - "\3\2\23\31\3\2\34$\3\2%&\4\2\3\3)*\3\2,/\3\2)*\3\2\60\63\3\2\64\65\3\2"+ - "CH\3\2IL\3\2pr\3\2NO\3\2Ze\2\u0294\2|\3\2\2\2\4\u0083\3\2\2\2\6\u0085"+ - "\3\2\2\2\b\u00a3\3\2\2\2\n\u00a5\3\2\2\2\f\u00a8\3\2\2\2\16\u00ae\3\2"+ - "\2\2\20\u00bf\3\2\2\2\22\u00c1\3\2\2\2\24\u00c7\3\2\2\2\26\u00cf\3\2\2"+ - "\2\30\u00d2\3\2\2\2\32\u00d5\3\2\2\2\34\u00d7\3\2\2\2\36\u00df\3\2\2\2"+ - " \u00e3\3\2\2\2\"\u00eb\3\2\2\2$\u00ed\3\2\2\2&\u00ff\3\2\2\2(\u0131\3"+ - "\2\2\2*\u0137\3\2\2\2,\u0141\3\2\2\2.\u0149\3\2\2\2\60\u0154\3\2\2\2\62"+ - "\u0158\3\2\2\2\64\u015a\3\2\2\2\66\u015c\3\2\2\28\u015e\3\2\2\2:\u0165"+ - "\3\2\2\2<\u0167\3\2\2\2>\u0169\3\2\2\2@\u016d\3\2\2\2B\u016f\3\2\2\2D"+ - "\u0171\3\2\2\2F\u0185\3\2\2\2H\u0187\3\2\2\2J\u0189\3\2\2\2L\u0191\3\2"+ - "\2\2N\u0193\3\2\2\2P\u0196\3\2\2\2R\u01a3\3\2\2\2T\u01a6\3\2\2\2V\u01b1"+ - "\3\2\2\2X\u01bc\3\2\2\2Z\u01c0\3\2\2\2\\\u01cb\3\2\2\2^\u01e3\3\2\2\2"+ - "`\u01e6\3\2\2\2b\u01f1\3\2\2\2d\u01f9\3\2\2\2f\u0201\3\2\2\2h\u020c\3"+ - "\2\2\2j\u0212\3\2\2\2l\u0223\3\2\2\2n\u022b\3\2\2\2p\u023b\3\2\2\2r\u023d"+ - "\3\2\2\2t\u0249\3\2\2\2v\u0252\3\2\2\2x{\5\4\3\2y{\7n\2\2zx\3\2\2\2zy"+ - "\3\2\2\2{~\3\2\2\2|z\3\2\2\2|}\3\2\2\2}\177\3\2\2\2~|\3\2\2\2\177\u0080"+ - "\7\2\2\3\u0080\3\3\2\2\2\u0081\u0084\5\16\b\2\u0082\u0084\5\6\4\2\u0083"+ - "\u0081\3\2\2\2\u0083\u0082\3\2\2\2\u0084\5\3\2\2\2\u0085\u0086\7\3\2\2"+ - "\u0086\u0088\5\66\34\2\u0087\u0089\5> \2\u0088\u0087\3\2\2\2\u0088\u0089"+ - "\3\2\2\2\u0089\u008a\3\2\2\2\u008a\u008b\5T+\2\u008b\u008c\7n\2\2\u008c"+ - "\7\3\2\2\2\u008d\u00a4\5\16\b\2\u008e\u00a4\5\24\13\2\u008f\u00a4\5\22"+ - "\n\2\u0090\u00a4\5\26\f\2\u0091\u00a4\5\30\r\2\u0092\u00a4\5\36\20\2\u0093"+ - "\u00a4\5 \21\2\u0094\u00a4\5\f\7\2\u0095\u00a4\5$\23\2\u0096\u00a4\5,"+ - "\27\2\u0097\u00a4\5j\66\2\u0098\u00a4\5n8\2\u0099\u00a4\5P)\2\u009a\u00a4"+ - "\5\\/\2\u009b\u00a4\5N(\2\u009c\u00a4\5\60\31\2\u009d\u00a4\5r:\2\u009e"+ - "\u00a4\5t;\2\u009f\u00a4\5v<\2\u00a0\u00a4\5\62\32\2\u00a1\u00a4\5\64"+ - "\33\2\u00a2\u00a4\5\n\6\2\u00a3\u008d\3\2\2\2\u00a3\u008e\3\2\2\2\u00a3"+ - "\u008f\3\2\2\2\u00a3\u0090\3\2\2\2\u00a3\u0091\3\2\2\2\u00a3\u0092\3\2"+ - "\2\2\u00a3\u0093\3\2\2\2\u00a3\u0094\3\2\2\2\u00a3\u0095\3\2\2\2\u00a3"+ - "\u0096\3\2\2\2\u00a3\u0097\3\2\2\2\u00a3\u0098\3\2\2\2\u00a3\u0099\3\2"+ - "\2\2\u00a3\u009a\3\2\2\2\u00a3\u009b\3\2\2\2\u00a3\u009c\3\2\2\2\u00a3"+ - "\u009d\3\2\2\2\u00a3\u009e\3\2\2\2\u00a3\u009f\3\2\2\2\u00a3\u00a0\3\2"+ - "\2\2\u00a3\u00a1\3\2\2\2\u00a3\u00a2\3\2\2\2\u00a4\t\3\2\2\2\u00a5\u00a6"+ - "\5\66\34\2\u00a6\u00a7\7\4\2\2\u00a7\13\3\2\2\2\u00a8\u00ac\7\5\2\2\u00a9"+ - "\u00ad\5> \2\u00aa\u00ad\5\66\34\2\u00ab\u00ad\58\35\2\u00ac\u00a9\3\2"+ - "\2\2\u00ac\u00aa\3\2\2\2\u00ac\u00ab\3\2\2\2\u00ad\r\3\2\2\2\u00ae\u00ba"+ - "\t\2\2\2\u00af\u00b1\5\20\t\2\u00b0\u00af\3\2\2\2\u00b0\u00b1\3\2\2\2"+ - "\u00b1\u00bb\3\2\2\2\u00b2\u00b7\5\20\t\2\u00b3\u00b4\7\17\2\2\u00b4\u00b6"+ - "\5\20\t\2\u00b5\u00b3\3\2\2\2\u00b6\u00b9\3\2\2\2\u00b7\u00b5\3\2\2\2"+ - "\u00b7\u00b8\3\2\2\2\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2\2\2\u00ba\u00b0"+ - "\3\2\2\2\u00ba\u00b2\3\2\2\2\u00bb\17\3\2\2\2\u00bc\u00c0\5F$\2\u00bd"+ - "\u00c0\5\66\34\2\u00be\u00c0\5> \2\u00bf\u00bc\3\2\2\2\u00bf\u00bd\3\2"+ - "\2\2\u00bf\u00be\3\2\2\2\u00c0\21\3\2\2\2\u00c1\u00c3\5\32\16\2\u00c2"+ + "\n8\38\58\u0238\n8\38\38\39\39\3:\3:\5:\u0240\n:\3:\3:\5:\u0244\n:\3:"+ + "\3:\3:\5:\u0249\n:\3:\3:\3;\3;\3;\5;\u0250\n;\3;\3;\5;\u0254\n;\3<\3<"+ + "\3<\5<\u0259\n<\3<\5<\u025c\n<\3<\3<\3<\3<\2\3&=\2\4\6\b\n\f\16\20\22"+ + "\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNPRTVXZ\\^`bdfhjlnp"+ + "rtv\2\20\3\2\6\16\3\2\23\31\3\2\34$\3\2%&\4\2\3\3)*\3\2,/\3\2)*\3\2\60"+ + "\63\3\2\64\65\3\2CH\3\2IL\3\2pr\3\2NO\3\2Ze\2\u0298\2|\3\2\2\2\4\u0083"+ + "\3\2\2\2\6\u0085\3\2\2\2\b\u00a3\3\2\2\2\n\u00a5\3\2\2\2\f\u00a8\3\2\2"+ + "\2\16\u00ae\3\2\2\2\20\u00bf\3\2\2\2\22\u00c1\3\2\2\2\24\u00c7\3\2\2\2"+ + "\26\u00cf\3\2\2\2\30\u00d2\3\2\2\2\32\u00d5\3\2\2\2\34\u00d7\3\2\2\2\36"+ + "\u00df\3\2\2\2 \u00e3\3\2\2\2\"\u00eb\3\2\2\2$\u00ed\3\2\2\2&\u00ff\3"+ + "\2\2\2(\u0131\3\2\2\2*\u0137\3\2\2\2,\u0141\3\2\2\2.\u0149\3\2\2\2\60"+ + "\u0154\3\2\2\2\62\u0158\3\2\2\2\64\u015a\3\2\2\2\66\u015c\3\2\2\28\u015e"+ + "\3\2\2\2:\u0165\3\2\2\2<\u0167\3\2\2\2>\u0169\3\2\2\2@\u016d\3\2\2\2B"+ + "\u016f\3\2\2\2D\u0171\3\2\2\2F\u0185\3\2\2\2H\u0187\3\2\2\2J\u0189\3\2"+ + "\2\2L\u0191\3\2\2\2N\u0193\3\2\2\2P\u0196\3\2\2\2R\u01a3\3\2\2\2T\u01a6"+ + "\3\2\2\2V\u01b1\3\2\2\2X\u01bc\3\2\2\2Z\u01c0\3\2\2\2\\\u01cb\3\2\2\2"+ + "^\u01e3\3\2\2\2`\u01e6\3\2\2\2b\u01f1\3\2\2\2d\u01f9\3\2\2\2f\u0201\3"+ + "\2\2\2h\u020c\3\2\2\2j\u0212\3\2\2\2l\u0223\3\2\2\2n\u022b\3\2\2\2p\u023b"+ + "\3\2\2\2r\u023d\3\2\2\2t\u024c\3\2\2\2v\u0255\3\2\2\2x{\5\4\3\2y{\7n\2"+ + "\2zx\3\2\2\2zy\3\2\2\2{~\3\2\2\2|z\3\2\2\2|}\3\2\2\2}\177\3\2\2\2~|\3"+ + "\2\2\2\177\u0080\7\2\2\3\u0080\3\3\2\2\2\u0081\u0084\5\16\b\2\u0082\u0084"+ + "\5\6\4\2\u0083\u0081\3\2\2\2\u0083\u0082\3\2\2\2\u0084\5\3\2\2\2\u0085"+ + "\u0086\7\3\2\2\u0086\u0088\5\66\34\2\u0087\u0089\5> \2\u0088\u0087\3\2"+ + "\2\2\u0088\u0089\3\2\2\2\u0089\u008a\3\2\2\2\u008a\u008b\5T+\2\u008b\u008c"+ + "\7n\2\2\u008c\7\3\2\2\2\u008d\u00a4\5\16\b\2\u008e\u00a4\5\24\13\2\u008f"+ + "\u00a4\5\22\n\2\u0090\u00a4\5\26\f\2\u0091\u00a4\5\30\r\2\u0092\u00a4"+ + "\5\36\20\2\u0093\u00a4\5 \21\2\u0094\u00a4\5\f\7\2\u0095\u00a4\5$\23\2"+ + "\u0096\u00a4\5,\27\2\u0097\u00a4\5j\66\2\u0098\u00a4\5n8\2\u0099\u00a4"+ + "\5P)\2\u009a\u00a4\5\\/\2\u009b\u00a4\5N(\2\u009c\u00a4\5\60\31\2\u009d"+ + "\u00a4\5r:\2\u009e\u00a4\5t;\2\u009f\u00a4\5v<\2\u00a0\u00a4\5\62\32\2"+ + "\u00a1\u00a4\5\64\33\2\u00a2\u00a4\5\n\6\2\u00a3\u008d\3\2\2\2\u00a3\u008e"+ + "\3\2\2\2\u00a3\u008f\3\2\2\2\u00a3\u0090\3\2\2\2\u00a3\u0091\3\2\2\2\u00a3"+ + "\u0092\3\2\2\2\u00a3\u0093\3\2\2\2\u00a3\u0094\3\2\2\2\u00a3\u0095\3\2"+ + "\2\2\u00a3\u0096\3\2\2\2\u00a3\u0097\3\2\2\2\u00a3\u0098\3\2\2\2\u00a3"+ + "\u0099\3\2\2\2\u00a3\u009a\3\2\2\2\u00a3\u009b\3\2\2\2\u00a3\u009c\3\2"+ + "\2\2\u00a3\u009d\3\2\2\2\u00a3\u009e\3\2\2\2\u00a3\u009f\3\2\2\2\u00a3"+ + "\u00a0\3\2\2\2\u00a3\u00a1\3\2\2\2\u00a3\u00a2\3\2\2\2\u00a4\t\3\2\2\2"+ + "\u00a5\u00a6\5\66\34\2\u00a6\u00a7\7\4\2\2\u00a7\13\3\2\2\2\u00a8\u00ac"+ + "\7\5\2\2\u00a9\u00ad\5> \2\u00aa\u00ad\5\66\34\2\u00ab\u00ad\58\35\2\u00ac"+ + "\u00a9\3\2\2\2\u00ac\u00aa\3\2\2\2\u00ac\u00ab\3\2\2\2\u00ad\r\3\2\2\2"+ + "\u00ae\u00ba\t\2\2\2\u00af\u00b1\5\20\t\2\u00b0\u00af\3\2\2\2\u00b0\u00b1"+ + "\3\2\2\2\u00b1\u00bb\3\2\2\2\u00b2\u00b7\5\20\t\2\u00b3\u00b4\7\17\2\2"+ + "\u00b4\u00b6\5\20\t\2\u00b5\u00b3\3\2\2\2\u00b6\u00b9\3\2\2\2\u00b7\u00b5"+ + "\3\2\2\2\u00b7\u00b8\3\2\2\2\u00b8\u00bb\3\2\2\2\u00b9\u00b7\3\2\2\2\u00ba"+ + "\u00b0\3\2\2\2\u00ba\u00b2\3\2\2\2\u00bb\17\3\2\2\2\u00bc\u00c0\5F$\2"+ + "\u00bd\u00c0\5\66\34\2\u00be\u00c0\5> \2\u00bf\u00bc\3\2\2\2\u00bf\u00bd"+ + "\3\2\2\2\u00bf\u00be\3\2\2\2\u00c0\21\3\2\2\2\u00c1\u00c3\5\32\16\2\u00c2"+ "\u00c4\5\34\17\2\u00c3\u00c2\3\2\2\2\u00c3\u00c4\3\2\2\2\u00c4\u00c5\3"+ "\2\2\2\u00c5\u00c6\5\66\34\2\u00c6\23\3\2\2\2\u00c7\u00c9\5\32\16\2\u00c8"+ "\u00ca\5\34\17\2\u00c9\u00c8\3\2\2\2\u00c9\u00ca\3\2\2\2\u00ca\u00cb\3"+ @@ -4450,22 +4461,23 @@ public class prog8Parser extends Parser { "\u0233\3\2\2\2\u0234\u0235\3\2\2\2\u0235\u0237\3\2\2\2\u0236\u0238\5l"+ "\67\2\u0237\u0236\3\2\2\2\u0237\u0238\3\2\2\2\u0238\u0239\3\2\2\2\u0239"+ "\u023a\7n\2\2\u023ao\3\2\2\2\u023b\u023c\t\17\2\2\u023cq\3\2\2\2\u023d"+ - "\u0240\7f\2\2\u023e\u0241\5:\36\2\u023f\u0241\5\66\34\2\u0240\u023e\3"+ - "\2\2\2\u0240\u023f\3\2\2\2\u0241\u0242\3\2\2\2\u0242\u0243\7g\2\2\u0243"+ - "\u0245\5&\24\2\u0244\u0246\7n\2\2\u0245\u0244\3\2\2\2\u0245\u0246\3\2"+ - "\2\2\u0246\u0247\3\2\2\2\u0247\u0248\5T+\2\u0248s\3\2\2\2\u0249\u024a"+ - "\7h\2\2\u024a\u024c\5&\24\2\u024b\u024d\7n\2\2\u024c\u024b\3\2\2\2\u024c"+ - "\u024d\3\2\2\2\u024d\u0250\3\2\2\2\u024e\u0251\5\b\5\2\u024f\u0251\5T"+ - "+\2\u0250\u024e\3\2\2\2\u0250\u024f\3\2\2\2\u0251u\3\2\2\2\u0252\u0255"+ - "\7i\2\2\u0253\u0256\5\b\5\2\u0254\u0256\5T+\2\u0255\u0253\3\2\2\2\u0255"+ - "\u0254\3\2\2\2\u0256\u0258\3\2\2\2\u0257\u0259\7n\2\2\u0258\u0257\3\2"+ - "\2\2\u0258\u0259\3\2\2\2\u0259\u025a\3\2\2\2\u025a\u025b\7j\2\2\u025b"+ - "\u025c\5&\24\2\u025cw\3\2\2\2Fz|\u0083\u0088\u00a3\u00ac\u00b0\u00b7\u00ba"+ + "\u023f\7f\2\2\u023e\u0240\5\32\16\2\u023f\u023e\3\2\2\2\u023f\u0240\3"+ + "\2\2\2\u0240\u0243\3\2\2\2\u0241\u0244\5:\36\2\u0242\u0244\5\66\34\2\u0243"+ + "\u0241\3\2\2\2\u0243\u0242\3\2\2\2\u0244\u0245\3\2\2\2\u0245\u0246\7g"+ + "\2\2\u0246\u0248\5&\24\2\u0247\u0249\7n\2\2\u0248\u0247\3\2\2\2\u0248"+ + "\u0249\3\2\2\2\u0249\u024a\3\2\2\2\u024a\u024b\5T+\2\u024bs\3\2\2\2\u024c"+ + "\u024d\7h\2\2\u024d\u024f\5&\24\2\u024e\u0250\7n\2\2\u024f\u024e\3\2\2"+ + "\2\u024f\u0250\3\2\2\2\u0250\u0253\3\2\2\2\u0251\u0254\5\b\5\2\u0252\u0254"+ + "\5T+\2\u0253\u0251\3\2\2\2\u0253\u0252\3\2\2\2\u0254u\3\2\2\2\u0255\u0258"+ + "\7i\2\2\u0256\u0259\5\b\5\2\u0257\u0259\5T+\2\u0258\u0256\3\2\2\2\u0258"+ + "\u0257\3\2\2\2\u0259\u025b\3\2\2\2\u025a\u025c\7n\2\2\u025b\u025a\3\2"+ + "\2\2\u025b\u025c\3\2\2\2\u025c\u025d\3\2\2\2\u025d\u025e\7j\2\2\u025e"+ + "\u025f\5&\24\2\u025fw\3\2\2\2Gz|\u0083\u0088\u00a3\u00ac\u00b0\u00b7\u00ba"+ "\u00bf\u00c3\u00c9\u00db\u00eb\u00ff\u0127\u0129\u012b\u0131\u0137\u013b"+ "\u0141\u0145\u014c\u0151\u0156\u0163\u016b\u0173\u0178\u017d\u0181\u0191"+ "\u019a\u019e\u01aa\u01ac\u01b4\u01b9\u01c3\u01c8\u01cf\u01d6\u01dc\u01e1"+ "\u01e9\u01ee\u01f7\u01fe\u0204\u0209\u0210\u0215\u0219\u021c\u021f\u0225"+ - "\u0229\u022d\u0231\u0234\u0237\u0240\u0245\u024c\u0250\u0255\u0258"; + "\u0229\u022d\u0231\u0234\u0237\u023f\u0243\u0248\u024f\u0253\u0258\u025b"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/docs/source/programming.rst b/docs/source/programming.rst index dc6e4a223..28919e145 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -328,8 +328,9 @@ Loops ----- The *for*-loop is used to let a variable (or register) iterate over a range of values. Iteration is done in steps of 1, but you can change this. -The loop variable must be declared as byte or word earlier. Floating point iteration is not supported, -if you want to loop over a floating-point array, use a loop with an integer index variable instead. +The loop variable can be declared as byte or word earlier so you can reuse it for multiple occasions, +or you can declare one directly in the for statement which will only be visible in the for loop body. +Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead. The *while*-loop is used to repeat a piece of code while a certain condition is still true. The *repeat--until* loop is used to repeat a piece of code until a certain condition is true. diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 97b37db39..4cbfcbb84 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -450,18 +450,34 @@ Loops for loop ^^^^^^^^ -The loop variable must be a register or a byte/word variable defined in the local scope. +The loop variable must be a register or a byte/word variable. It must be defined in the local scope (to reuse +an existing variable), or you can declare it in the for loop directly to make a new one that is only visible +in the body of the for loop. The expression that you loop over can be anything that supports iteration (such as ranges like ``0 to 100``, array variables and strings) *except* floating-point arrays (because a floating-point loop variable is not supported). You can use a single statement, or a statement block like in the example below:: - for in [ step ] { + for [byte | word] in [ step ] { ; do something... break ; break out of the loop continue ; immediately enter next iteration } +For example, this is a for loop using the existing byte variable ``i`` to loop over a certain range of numbers:: + + for i in 20 to 155 { + ; do something + } + +And this is a loop over the values of the array ``fibonacci_numbers`` where the loop variable is declared in the loop itself:: + + word[20] fibonacci_numbers = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181] + + for word fibnr in fibonacci_numbers { + ; do something + } + while loop ^^^^^^^^^^ diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5c25975db..6ec2664f8 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,112 +3,6 @@ TODO ==== -IF_XX:: - - if[_XX] [] { - ... - } - [ else { - ... ; evaluated when the condition is not met - } ] - - -==> DESUGARING ==> - -(no else:):: - - if[_!XX] [] goto prog8_if_999_end ; !XX being the conditional inverse of XX - .... (true part) - prog8_if_999_end ; code continues after this - - -(with else):: - - if[_XX] [] goto prog8_if_999 - ... (else part) - goto prog8_if_999_end - prog8_if_999 ... (true part) - prog8_if_999_end ; code continues after this - - -IF X Y - -==> DESUGARING ==>:: - - compare X, Y - if_XX goto .... - XX based on . - - -While:: - - while[_XX] { - ... - continue - break - } - -==> DESUGARING ==>:: - - goto prog8_while_999_check ; jump to the check - prog8_while_999 - ... (code) - goto prog8_while_999 ;continue - goto prog8_while_999_end ;break - prog8_while_999_check - if[_XX] goto prog8_while_999 ; loop condition - prog8_while_999_end ; code continues after this - - -Repeat:: - - repeat { - ... - continue - break - } until[_XX] - -==> DESUGARING ==>:: - - prog8_repeat_999 - ... (code) - goto prog8_repeat_999 ;continue - goto prog8_repeat_999_end ;break - if[_!XX] goto prog8_repeat_999 ; loop condition via conditional inverse of XX - prog8_repeat_999_end ; code continues after this - - -For:: - - for = to [step ] { - ... - break - continue - } - - -@todo how to do signed integer loopvars? - - -==> DESUGARING ==>:: - - loopvar = - compare loopvar, - if_ge goto prog8_for_999_end ; loop condition - step = ; (store only if step < -1 or step > 1) - prog8_for_999 - goto prog8_for_999_end ;break - goto prog8_for_999_loop ;continue - .... (code) - prog8_for_999_loop - loopvar += step ; (if step > 1 or step < -1) - loopvar++ ; (if step == 1) - loopvar-- ; (if step == -1) - goto prog8_for_999 ; continue the loop - prog8_for_999_end ; code continues after this - - - ### Macros @todo macros are meta-code that is executed by the compiler, in a preprecessing step