diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index f29a04d..9ce432f 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -32,7 +32,7 @@ class VM this(Code[] code, int len, int[wstring] globalTable) { this.code = code; - this.stack = new Value[1024 * 1024]; + this.stack = new Value[16384]; this.global = new Value[len]; this.globalTable = globalTable; foreach(wstring k, int v ; globalTable) @@ -68,6 +68,10 @@ class VM { return global[globalTable[name]]; } + void end() + { + pc = code.length; + } } enum CodeType { @@ -82,6 +86,8 @@ enum CodeType GotoS, GotoFalse, GotoTrue, + GosubS, + ReturnSubroutine, } abstract class Code { @@ -420,7 +426,60 @@ class GotoFalse : Code vm.pc = address - 1; } } -class Gosub : Code +class GosubAddr : Code { - + int address; + this(int addr) + { + this.type = CodeType.Gosub; + address = addr; + } + override void execute(VM vm) + { + vm.push(Value(vm.pc)); + vm.pc = address - 1; + } } +class GosubS : Code +{ + wstring label; + this(wstring label) + { + this.type = CodeType.GosubS; + this.label = label; + } + override void execute(VM vm) + { + stderr.writeln("can't execute"); + } +} +class ReturnSubroutine : Code +{ + this() + { + this.type = CodeType.ReturnSubroutine; + } + override void execute(VM vm) + { + Value pc; + vm.pop(pc); + if(pc.type != ValueType.Integer || pc.integerValue < 0 || pc.integerValue >= vm.code.length) + { + stderr.writeln("Internal error:Compiler bug?"); + readln(); + return; + } + vm.pc = pc.integerValue; + } +} +class EndVM : Code +{ + this() + { + } + override void execute(VM vm) + { + vm.end(); + } +} + diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 0d85654..11f9fe1 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -42,6 +42,10 @@ class Compiler { code ~= new GotoS(label); } + void genCodeGosub(wstring label) + { + code ~= new GosubS(label); + } GotoAddr genCodeGoto() { auto c = new GotoAddr(-1); @@ -258,6 +262,26 @@ class Compiler case NodeType.For: compileFor(cast(For)i); break; + case NodeType.Gosub: + { + auto gosub = cast(Gosub)i; + genCodeGosub(gosub.label); + } + break; + case NodeType.Return: + { + auto ret = cast(Return)i; + if(ret.expression is null) + genCode(new ReturnSubroutine()); + else + { + //関数未実装:error + } + } + break; + case NodeType.End: + genCode(new EndVM()); + break; default: stderr.writeln("Compile:NotImpl ", i.type); } @@ -274,6 +298,10 @@ class Compiler { code[i] = new GotoAddr(globalLabel[(cast(GotoS)c).label]); } + if(c.type == CodeType.GosubS) + { + code[i] = new GosubAddr(globalLabel[(cast(GosubS)c).label]); + } } return new VM(code, globalIndex + 1, global); } diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 4fae60b..01daf37 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -44,7 +44,12 @@ FOR I=0 TO 100 ENDIF ENDIF NEXT -?NOT 1,!!\"a\" +?@HELLOWORLD +GOSUB @A +END +@A +?\"SUBROUTINE TEST\" +RETURN "); version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring); auto vm = parser.compile(); diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 1443769..d499f47 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -23,6 +23,9 @@ enum NodeType Goto, If, For, + Gosub, + Return, + End, } abstract class Node { @@ -245,3 +248,29 @@ class For : Statement this.statements = statements; } } +class Gosub : Statement +{ + wstring label; + this(wstring name) + { + this.type = NodeType.Gosub; + this.label = name; + } +} +class Return : Statement +{ + Expression expression; + this(Expression expression) + { + this.type = NodeType.Return; + this.expression = expression; + } +} +class End : Statement +{ + this() + { + this.type = NodeType.End; + } +} + diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 1b5dd72..3c72bc5 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -49,6 +49,9 @@ class Lexical reserved["FOR"] = TokenType.For; reserved["NEXT"] = TokenType.Next; reserved["MOD"] = TokenType.Mod; + reserved["GOSUB"] = TokenType.Gosub; + reserved["RETURN"] = TokenType.Return; + reserved["END"] = TokenType.End; reserved.rehash(); line = 1; } @@ -472,7 +475,24 @@ class Parser case TokenType.Goto: lex.popFront(); token = lex.front(); - node = new Goto(token.value.stringValue); + if(token.type == TokenType.Label) + node = new Goto(token.value.stringValue); + else + { + writeln("NotImpl"); + syntaxError(); + } + break; + case TokenType.Gosub: + lex.popFront(); + token = lex.front(); + if(token.type == TokenType.Label) + node = new Gosub(token.value.stringValue); + else + { + writeln("NotImpl"); + syntaxError(); + } break; case TokenType.If: node = if_(); @@ -480,6 +500,13 @@ class Parser case TokenType.For: node = forStatement(); break; + case TokenType.Return: + lex.popFront(); + node = new Return(expression()); + return node; + case TokenType.End: + node = new End(); + break; default: syntaxError(); break; @@ -741,7 +768,7 @@ class Parser break; case TokenType.Label://3.1 //文字列リテラル - + node = new Constant(token.value); break; case TokenType.Minus: //TODO:UnaryOperatorの実装 diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index e5eea76..f334b5b 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -44,6 +44,9 @@ enum TokenType LogicalAnd,//&& LogicalOr,//|| IntDiv,//DIV + Gosub, + Return, + End, } struct Token