diff --git a/SMILEBASIC/TEST.txt b/SMILEBASIC/TEST.txt index 29ff2f1..4208f1a 100644 --- a/SMILEBASIC/TEST.txt +++ b/SMILEBASIC/TEST.txt @@ -1,3 +1,44 @@ + +VAR IFTEST=FALSE +IF TRUE THEN + IFTEST=TRUE +ENDIF +ASSERT__ IFTEST, "IF" + +VAR IFTEST2=FALSE +IF TRUE THEN IFTEST2=TRUE +ASSERT__ IFTEST2, "IF" + +VAR ELSETEST=FALSE +IF FALSE THEN +ELSE + ELSETEST=TRUE +ENDIF +ASSERT__ ELSETEST, "ELSE" + +VAR ELSETEST2=FALSE +IF FALSE THEN ELSE ELSETEST2=TRUE:ENDIF +ASSERT__ ELSETEST2, "ELSE" + + +VAR ELSEIFTEST=FALSE +IF FALSE THEN + ELSEIFTEST=FALSE +ELSEIF FALSE THEN + ELSEIFTEST=FALSE +ELSEIF TRUE THEN + ELSEIFTEST=TRUE +ELSEIF FALSE THEN + ELSEIFTEST=FALSE +ELSE + ELSEIFTEST=FALSE +ENDIF +ASSERT__ ELSEIFTEST, "ELSEIFTEST" + +VAR ELSEIFTEST2=FALSE +IF FALSE THEN ELSEIFTEST2=FALSE ELSEIF FALSE THEN ELSEIFTEST2=FALSE ELSEIF TRUE THEN ELSEIFTEST2=TRUE ELSEIF FALSE THEN ELSEIFTEST2=FALSE ELSE ELSEIFTEST2=FALSE ENDIF +ASSERT__ ELSEIFTEST2, "ELSEIFTEST" + DEF CALLTEST(V) RETURN V END diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 0331460..e11a020 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -656,7 +656,46 @@ class Compiler compileStatements(node.then, sc); //もしelseもあるのならば、endifに飛ぶ GotoAddr then; - if(node.hasElse) + /* + 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(); + else_.address = cast(int)code.length; + GotoFalse else2; + foreach(t; node.elseif) + { + compileExpression(t[1], sc); + else2 = genCodeGotoFalse(); + compileStatements(t[0], sc); + genCode(then); + else2.address = cast(int)code.length; + } + if(node.hasElse) + compileStatements(node.else_, sc); + then.address = cast(int)code.length; + } + else if(node.hasElse) { then = genCodeGoto(); else_.address = cast(int)code.length; diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index dcc0e7d..62425a0 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -247,21 +247,28 @@ class Goto : Statement } class If : Statement { + import std.typecons; Expression condition; Statements then; Statements else_; - this(Expression condition, Statements t, Statements e, SourceLocation loc) + Tuple!(Statements, Expression)[] elseif; + this(Expression condition, Statements t, Statements e, Tuple!(Statements, Expression)[] elif, SourceLocation loc) { super.location = loc; this.type = NodeType.If; this.condition = condition; this.then = t; this.else_ = e; + this.elseif = elif; } bool hasElse() { return !(else_ is null) && else_.statements.length != 0; } + bool hasElseif() + { + return !(elseif is null) && elseif.length != 0; + } } class For : Statement { diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 40009ab..c2a9604 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -78,6 +78,7 @@ class Lexical reserved["COMMON"] = TokenType.Common; reserved["USE"] = TokenType.Use; reserved["EXEC"] = TokenType.Exec; + reserved["ELSEIF"] = TokenType.Elseif; reserved.rehash(); } this(wstring input) @@ -708,6 +709,7 @@ class Parser flag = false; if(type == TokenType.NewLine) break; if(type == TokenType.Else) break; + if(type == TokenType.Elseif) break; if(type == TokenType.Endif) break; if(type == TokenType.Label) { @@ -730,6 +732,7 @@ class Parser { auto type = lex.front().type; if(type == TokenType.Else) break; + if(type == TokenType.Elseif) break; if(type == TokenType.Endif) break; auto statement = statement(); if(statement != Statement.NOP) @@ -1388,6 +1391,47 @@ class Parser } token = lex.front(); lex.popFront(); + import std.typecons; + Tuple!(Statements, Expression)[] elseif = new Tuple!(Statements, Expression)[0]; + while(token.type == TokenType.Elseif) + { + token = lex.front(); + auto elseifcond = expression(); + if(elseifcond is null) + { + syntaxError(); + return null; + } + token = lex.front(); + if(token.type != TokenType.Then) + { + if(token.type != TokenType.Goto) + { + //IF expr GOSUBは不可 + syntaxError(); + return null; + } + } + if(token.type != TokenType.Goto) + { + lex.popFront(); + token = lex.front(); + } + if(!multiline && lex.front().type == TokenType.NewLine) + { + syntaxError(); + } + if(multiline) + { + elseif ~= tuple(multilineIfStatements(), elseifcond); + } + else + { + elseif ~= tuple(ifStatements(), elseifcond); + } + token = lex.front(); + lex.popFront(); + } Statements else_; if(token.type == TokenType.Else) { @@ -1399,14 +1443,14 @@ class Parser if(multiline) { else_ = multilineIfStatements(); - lex.popFront(); } else { else_ = ifStatements(); } + lex.popFront(); } - auto if_ = new If(expr, then, else_, lex.location); + auto if_ = new If(expr, then, else_, elseif, lex.location); return if_; } Assign assign(wstring name) @@ -1449,14 +1493,16 @@ class Parser } if(token.type != TokenType.Colon && token.type != TokenType.NewLine && token.type != TokenType.Semicolon && token.type != TokenType.Comma && - token.type != TokenType.Else && token.type != TokenType.Endif) + token.type != TokenType.Else && token.type != TokenType.Endif && + token.type != TokenType.Elseif && token.type != TokenType.Print) { syntaxError(); } else { if(token.type == TokenType.Colon || token.type == TokenType.NewLine || - token.type == TokenType.Else || token.type == TokenType.Endif) + token.type == TokenType.Else || token.type == TokenType.Endif || + token.type == TokenType.Elseif || token.type == TokenType.Print) { print.addLine(); break; diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index d32fd20..99d3cd8 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -69,6 +69,7 @@ enum TokenType Exec, Call, Common, + Elseif, } struct Token