diff --git a/SMILEBASIC/TEST.txt b/SMILEBASIC/TEST.txt index 4208f1a..ad456d1 100644 --- a/SMILEBASIC/TEST.txt +++ b/SMILEBASIC/TEST.txt @@ -1,3 +1,35 @@ +'REPEAT TEST +?"REPEAT(1)" +VAR REPEATTEST +REPEAT + REPEATTEST=TRUE + BREAK + ASSERT__ FALSE, "REPEAT" +UNTIL FALSE +ASSERT__ REPEATTEST, "REPEAT" + +?"REPEAT(2)" +VAR REPEATTEST2 +REPEAT + REPEATTEST2=1 + CONTINUE + ASSERT__ FALSE, "REPEAT" +UNTIL REPEATTEST2 +ASSERT__ REPEATTEST2, "REPEAT" + +?"REPEAT(3)" +REPEAT + CONTINUE + ASSERT__ FALSE, "REPEAT" +UNTIL TRUE + +?"REPEAT(4)" +VAR REPEATTEST4 +REPEAT + REPEATTEST4=TRUE +UNTIL TRUE +ASSERT__ REPEATTEST4, "REPEAT" + VAR IFTEST=FALSE IF TRUE THEN diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index e11a020..5c61720 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -656,28 +656,6 @@ class Compiler compileStatements(node.then, sc); //もしelseもあるのならば、endifに飛ぶ GotoAddr then; - /* - if 0 then - elseif 0 then - elseif 1 then - else - endif - push 0 - gotofalse else - goto endif - else: - push 0 - gototrue elif1else - push 1 - gototrue elif2 - goto else - elif1: - goto endif - elif2: - goto endif - else: - endif: - */ if (node.hasElseif) { then = genCodeGoto(); @@ -765,6 +743,17 @@ class Compiler s.breakAddr.address = cast(int)code.length; breakAddr.address = cast(int)code.length; } + void compileRepeat(RepeatUntil node, Scope s) + { + auto start = cast(int)code.length; + s = new Scope(new GotoAddr(-1), new GotoAddr(-1), s); + compileStatements(node.statements, s); + s.continueAddr.address = cast(int)code.length; + compileExpression(node.condExpression, s); + auto a = genCodeGotoFalse(); + a.address = start; + s.breakAddr.address = cast(int)code.length; + } void compileVar(Var node, Scope sc) { foreach(Statement v ; node.define) @@ -1096,6 +1085,9 @@ class Compiler case NodeType.Input: compileInput(cast(Input)i, s); break; + case NodeType.RepeatUntil: + compileRepeat(cast(RepeatUntil)i, s); + break; default: stderr.writeln("Compile:NotImpl ", i.type); } diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 62425a0..4d49af4 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -41,6 +41,7 @@ enum NodeType Restore, On, Input, + RepeatUntil, } abstract class Node { @@ -564,3 +565,16 @@ class Input : Statement variables ~= lvalue; } } + +class RepeatUntil : Statement +{ + Expression condExpression; + Statements statements; + this(Expression condExpression, Statements statements, SourceLocation loc) + { + super.location = loc; + this.type = NodeType.RepeatUntil; + this.condExpression = condExpression; + this.statements = statements; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index c2a9604..391ecac 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -79,6 +79,8 @@ class Lexical reserved["USE"] = TokenType.Use; reserved["EXEC"] = TokenType.Exec; reserved["ELSEIF"] = TokenType.Elseif; + reserved["REPEAT"] = TokenType.Repeat; + reserved["UNTIL"] = TokenType.Until; reserved.rehash(); } this(wstring input) @@ -788,6 +790,21 @@ class Parser lex.popFront(); return statements; } + Statements repeatStatements() + { + auto statements = new Statements(lex.location); + while(!lex.empty()) + { + auto type = lex.front().type; + if(type == TokenType.Until) break; + auto statement = statement(); + if(statement != Statement.NOP) + { + statements.addStatement(statement); + } + } + return statements; + } void syntaxError() { stderr.writeln("Syntax error (", lex.getLine(), ')', " Mysterious ", lex.front().type); @@ -944,6 +961,9 @@ class Parser case TokenType.While: node = whileStatement(); break; + case TokenType.Repeat: + node = repeatStatement(); + break; case TokenType.Inc: case TokenType.Dec: return incStatement(); @@ -1352,6 +1372,27 @@ class Parser auto node = new While(expr, statements, lex.location); return node; } + RepeatUntil repeatStatement() + { + lex.popFront(); + Statements statements = repeatStatements(); + auto token = lex.front; + if (token.type != TokenType.Until) + { + //TODO:REPEAT without UNTIL + syntaxError(); + return null; + } + lex.popFront(); + auto expr = expression(); + if(expr is null) + { + syntaxError(); + return null; + } + auto node = new RepeatUntil(expr, statements, lex.location); + return node; + } If if_() { lex.popFront(); diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index 99d3cd8..4500d8f 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -70,6 +70,8 @@ enum TokenType Call, Common, Elseif, + Repeat, + Until, } struct Token