From 5cab924046c6d62f1e243d3f4ef3fcce6ed089c7 Mon Sep 17 00:00:00 2001 From: otya128 Date: Sat, 6 Jun 2015 17:11:02 +0900 Subject: [PATCH] =?UTF-8?q?IF=E3=81=AE=E6=A7=8B=E6=96=87=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SMILEBASIC/VM.d | 34 ++++++++++++++++ SMILEBASIC/main.d | 6 ++- SMILEBASIC/node.d | 14 +++++++ SMILEBASIC/parser.d | 98 ++++++++++++++++++++++++++++++++++++++++----- SMILEBASIC/token.d | 3 ++ SMILEBASIC/type.d | 15 +++++++ 6 files changed, 160 insertions(+), 10 deletions(-) diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 26936d3..64f16db 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -51,6 +51,8 @@ enum CodeType Print, PopG, GotoS, + GotoFalse, + GotoTrue, } abstract class Code { @@ -194,6 +196,38 @@ class GotoS : Code stderr.writeln("can't execute"); } } +class GotoTrue : Code +{ + int address; + this(int addr) + { + this.type = CodeType.GotoTrue; + address = addr; + } + override void execute(VM vm) + { + Value cond; + vm.pop(cond); + if(cond.boolValue) + vm.pc = address - 1; + } +} +class GotoFalse : Code +{ + int address; + this(int addr) + { + this.type = CodeType.GotoFalse; + address = addr; + } + override void execute(VM vm) + { + Value cond; + vm.pop(cond); + if(!cond.boolValue) + vm.pc = address - 1; + } +} class Gosub : Code { diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 89d58ff..719fd7b 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -8,7 +8,11 @@ int main(string[] argv) writeln(parser.calc()); } - auto parser = new Parser("@A\nA=1+2+3+4\nPRINT 1+1,2+3;10-5,A:A=A*2:PRINT A:GOTO@A"); + auto parser = new Parser( +"@A\nA=1+2+3+4\nPRINT 1+1,2+3;10-5,A:A=A*2:PRINT A +IF 1 THEN PRINT 2 +IF 3 THEN PRINT 4 ELSE PRINT 5 +"); auto vm = parser.compile(); vm.run(); readln(); diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 710a1ed..96c5d57 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -20,6 +20,7 @@ enum NodeType Print, Label, Goto, + If, } abstract class Node { @@ -191,3 +192,16 @@ class Goto : Statement this.label = name; } } +class If : Statement +{ + Expression condition; + Statements then; + Statements else_; + this(Expression condition, Statements t, Statements e) + { + this.type = NodeType.If; + this.condition = condition; + this.then = t; + this.else_ = e; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 98f8bbb..2e5307f 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -39,6 +39,10 @@ class Lexical reserved["NOT"] = TokenType.Not; reserved["PRINT"] = TokenType.Print; reserved["GOTO"] = TokenType.Goto; + reserved["IF"] = TokenType.If; + reserved["THEN"] = TokenType.Then; + reserved["ELSE"] = TokenType.Else; + reserved["ENDIF"] = TokenType.Endif; reserved.rehash(); line = 1; } @@ -289,6 +293,7 @@ class Parser } Statements parseProgram() { + lex.popFront(); auto statements = new Statements(); while(!lex.empty()) { @@ -302,19 +307,37 @@ class Parser } return statements; } + Statements ifstatements() + { + auto statements = new Statements(); + while(!lex.empty()) + { + auto type = lex.front().type; + if(type == TokenType.NewLine) break; + if(type == TokenType.Else) break; + if(type == TokenType.Endif) break; + auto statement = statement(); + if(statement != Statement.NOP) + { + statements.addStatement(statement); + } + } + return statements; + } void syntaxError() { - stderr.writeln("Syntax error (", lex.getLine(), ')'); + stderr.writeln("Syntax error (", lex.getLine(), ')', " Mysterious ", lex.front().type); } //statement Statement statement() { - lex.popFront(); auto token = lex.front(); + Statement node = null; switch(token.type) { case TokenType.Print: - return print(); + node = print(); + return node; case TokenType.Iden: { wstring name = token.value.stringValue; @@ -322,7 +345,8 @@ class Parser token = lex.front(); if(token.type == TokenType.Assign) { - return assign(name); + node = assign(name); + break; } //命令呼び出し } @@ -331,16 +355,69 @@ class Parser case TokenType.NewLine: break; case TokenType.Label: - return new Label(token.value.stringValue); + node = new Label(token.value.stringValue); + break; case TokenType.Goto: lex.popFront(); token = lex.front(); - return new Goto(token.value.stringValue); + node = new Goto(token.value.stringValue); + break; + case TokenType.If: + node = if_(); + return node; default: syntaxError(); break; } - return null; + lex.popFront(); + return node; + } + If if_() + { + lex.popFront(); + auto token = lex.front(); + auto expr = expression(); + if(expr 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(token.type == TokenType.NewLine) + { + writeln("NotImpl: Multi line if"); + syntaxError(); + return null; + } + auto then = ifstatements(); + token = lex.front(); + lex.popFront(); + Statements else_; + if(token.type == TokenType.Else) + { + if(lex.front().type == TokenType.NewLine) + { + //3.1現在だとエラー + syntaxError(); + } + else_ = ifstatements(); + } + auto if_ = new If(expr, then, else_); + return if_; } Assign assign(wstring name) { @@ -379,13 +456,16 @@ class Parser print.addLine(); break; } - if(token.type != TokenType.Colon && token.type != TokenType.NewLine && token.type != TokenType.Semicolon && token.type != TokenType.Comma) + 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) { syntaxError(); } else { - if(token.type == TokenType.Colon || token.type == TokenType.NewLine) + if(token.type == TokenType.Colon || token.type == TokenType.NewLine || + token.type == TokenType.Else || token.type == TokenType.Endif) { print.addLine(); break; diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index 05a59a4..32f2acb 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -27,6 +27,9 @@ enum TokenType Assign, Label, Goto, + Then, + Else, + Endif, } struct Token diff --git a/SMILEBASIC/type.d b/SMILEBASIC/type.d index 5e374a2..6d66939 100644 --- a/SMILEBASIC/type.d +++ b/SMILEBASIC/type.d @@ -45,4 +45,19 @@ struct Value break; } } + bool boolValue() + { + switch(type) + { + case ValueType.Double: + return this.doubleValue != 0; + case ValueType.Integer: + return this.integerValue != 0; + case ValueType.String: + return true;//3.1現在では文字列はtrue(ただし!"A"などは動かない) + default: + //配列はtype missmatch + return false; + } + } }