From 65fe8558a24c46eeb123423fd2778cc44c26a480 Mon Sep 17 00:00:00 2001 From: otya128 Date: Sun, 7 Jun 2015 13:28:19 +0900 Subject: [PATCH] =?UTF-8?q?FOR=E3=82=92=E5=AE=9F=EF=BF=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SMILEBASIC/VM.d | 23 +++++++++ SMILEBASIC/compiler.d | 71 ++++++++++++++++++++++++++ SMILEBASIC/main.d | 9 +++- SMILEBASIC/node.d | 24 +++++++++ SMILEBASIC/parser.d | 113 ++++++++++++++++++++++++++++++++++++++++-- SMILEBASIC/token.d | 8 +++ 6 files changed, 243 insertions(+), 5 deletions(-) diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 64f16db..a9048ee 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -33,6 +33,11 @@ class VM } void pop(out Value value) { + if(stacki <= 0) + { + writeln("Stack underflow"); + readln(); + } value = stack[--stacki]; } Value testGetGlobaVariable(wstring name) @@ -162,6 +167,24 @@ class Operate : Code case TokenType.Div: ld /= rd; break; + case TokenType.Equal: + ld = ld == rd; + break; + case TokenType.NotEqual: + ld = ld != rd; + break; + case TokenType.Less: + ld = ld < rd; + break; + case TokenType.LessEqual: + ld = ld <= rd; + break; + case TokenType.Greater: + ld = ld > rd; + break; + case TokenType.GreaterEqual: + ld = ld >= rd; + break; default: writeln("NotImpl: ", operator); break; diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 8c41dc9..b6563b1 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -17,6 +17,10 @@ class Compiler int[wstring] global; int[wstring] globalLabel; int globalIndex = 0; + void genCode(Code c) + { + code ~= c; + } void genCodeImm(Value value) { code ~= new Push(value); @@ -43,6 +47,12 @@ class Compiler code ~= c; return c; } + GotoAddr genCodeGoto(int addr) + { + auto c = new GotoAddr(addr); + code ~= c; + return c; + } GotoTrue genCodeGotoTrue() { auto c = new GotoTrue(-1); @@ -137,6 +147,64 @@ class Compiler else_.address = code.length; } } + void compileFor(For node) + { + compileStatement(node.initExpression); + auto forstart = code.length; + compileExpression(node.stepExpression); + genCodeImm(Value(0)); + //step>=0 + genCodeOP(TokenType.GreaterEqual); + auto positiveZero = genCodeGotoTrue();//正の値または0 + //stepが負の値の時の処理 + //toよりcounterが小さい場合はBREAK + //to==counterの時はBREAKしない + //t c + //0>0 false + //FOR I=0 TO -1 STEP -1 + //-1>0 false + //1>0 true +/* + genCodeImm(Value("Helloneg\n")); + compileExpression(node.toExpression); + genCodeImm(Value("\nTo\n")); + compileExpression(node.stepExpression); + genCodeImm(Value("Step\n")); + */ + //code ~= new PrintCode(5); + compileExpression(node.toExpression); + genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); + genCodeOP(TokenType.Greater); + auto breakAddr = genCodeGotoTrue(); + auto forAddr = genCodeGoto(); + positiveZero.address = code.length; + //stepが正の値の時の処理 + //toよりcounterが大きい場合はBREAK + //t c + //0<0 false + //1<0 false + //0<1 true break + /* + genCodeImm(Value("HelloPositive\n")); + compileExpression(node.toExpression); + genCodeImm(Value("\nTo\n")); + compileExpression(node.stepExpression); + genCodeImm(Value("Step\n")); + code ~= new PrintCode(5);*/ + compileExpression(node.toExpression); + genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); + genCodeOP(TokenType.Less); + genCode(breakAddr); + forAddr.address = code.length; + compileStatements(node.statements); + //counterに加算する + genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); + compileExpression(node.stepExpression); + genCodeOP(TokenType.Plus); + genCodePopGlobal(getGlobalVarIndex(node.initExpression.name)); + genCodeGoto(forstart); + breakAddr.address = code.length; + } void compileStatements(Statements statements) { @@ -193,6 +261,9 @@ class Compiler case NodeType.If: compileIf(cast(If)i); break; + case NodeType.For: + compileFor(cast(For)i); + break; default: stderr.writeln("Compile:NotImpl ", i.type); } diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 7cb7939..e915c38 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -9,14 +9,19 @@ int main(string[] argv) } 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 +//"@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 0 THEN PRINT 4 ELSE PRINT 5 IF 0 THEN PRINT 111 ELSE PRINT 222 ENDIF + +FOR I=-2 TO -9 STEP -2 + PRINT I +NEXT +?I "); auto vm = parser.compile(); vm.run(); diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 9ad45b7..8721b95 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -21,6 +21,7 @@ enum NodeType Label, Goto, If, + For, } abstract class Node { @@ -209,3 +210,26 @@ class If : Statement return !(else_ is null) && else_.statements.length != 0; } } +class For : Statement +{ + Assign initExpression; + Expression toExpression; + Expression stepExpression; + Statements statements; + this(Assign assign, Expression toExpression, Expression stepExpression, Statements statements) + { + this.type = NodeType.For; + this.initExpression = assign; + this.toExpression = toExpression; + this.stepExpression = stepExpression; + this.statements = statements; + } + this(Assign assign, Expression toExpression, Statements statements) + { + this.type = NodeType.For; + this.initExpression = assign; + this.toExpression = toExpression; + this.stepExpression = null; + this.statements = statements; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 77719d5..9294903 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -33,6 +33,8 @@ class Lexical table['\n'] = TokenType.NewLine; table['?'] = TokenType.Print; table['='] = TokenType.Assign; + table['<'] = TokenType.Less; + table['>'] = TokenType.Greater; reserved["OR"] = TokenType.Or; reserved["AND"] = TokenType.And; reserved["XOR"] = TokenType.Xor; @@ -43,6 +45,8 @@ class Lexical reserved["THEN"] = TokenType.Then; reserved["ELSE"] = TokenType.Else; reserved["ENDIF"] = TokenType.Endif; + reserved["FOR"] = TokenType.For; + reserved["NEXT"] = TokenType.Next; reserved.rehash(); line = 1; } @@ -111,6 +115,21 @@ class Lexical token = Token(TokenType.Iden, Value(iden)); break; } + if(c == '"') + { + i++; + wstring str; + for(;i < code.length;i++) + { + c = code[i]; + if(c == '"')//"を閉じない文も許容 + { + i++; + break; + } + str ~= c; + } + } if(c == '@') { //ラベル(もしくは文字列) @@ -129,7 +148,30 @@ class Lexical token = Token(TokenType.Label, Value(iden)); break; } - + if(c == '=' && i + 1 < code.length && code[i + 1] == '=') + { + token = Token(TokenType.Equal); + i += 2; + break; + } + if(c == '!' && i + 1 < code.length && code[i + 1] == '=') + { + token = Token(TokenType.NotEqual); + i += 2; + break; + } + if(c == '<' && i + 1 < code.length && code[i + 1] == '=') + { + token = Token(TokenType.LessEqual); + i += 2; + break; + } + if(c == '>' && i + 1 < code.length && code[i + 1] == '=') + { + token = Token(TokenType.GreaterEqual); + i += 2; + break; + } if(table[cast(char)c] == TokenType.Unknown) { //error @@ -340,6 +382,22 @@ class Parser } return statements; } + Statements forStatements() + { + auto statements = new Statements(); + while(!lex.empty()) + { + auto type = lex.front().type; + if(type == TokenType.Next) break; + auto statement = statement(); + if(statement != Statement.NOP) + { + statements.addStatement(statement); + } + } + lex.popFront(); + return statements; + } void syntaxError() { stderr.writeln("Syntax error (", lex.getLine(), ')', " Mysterious ", lex.front().type); @@ -362,7 +420,7 @@ class Parser if(token.type == TokenType.Assign) { node = assign(name); - break; + return node; } //命令呼び出し } @@ -381,6 +439,9 @@ class Parser case TokenType.If: node = if_(); return node; + case TokenType.For: + node = forStatement(); + break; default: syntaxError(); break; @@ -388,6 +449,45 @@ class Parser lex.popFront(); return node; } + For forStatement() + { + For node; + lex.popFront(); + Statement initStatement = statement(); + if(initStatement.type != NodeType.Assign) + { + syntaxError(); + return null; + } + Assign init = cast(Assign)initStatement; + + auto token = lex.front(); + //TO,STEPは予約語ではない + if(token.type != TokenType.Iden || token.value.stringValue != "TO") + { + syntaxError(); + return null; + } + lex.popFront(); + Expression to = expression(); + token = lex.front(); + Expression step; + //TO,STEPは予約語ではない + if(token.type == TokenType.Iden && token.value.stringValue == "STEP") + { + lex.popFront(); + step = expression(); + } + else + { + //とりあえず + step = new Constant(Value(1)); + } + token = lex.front(); + Statements statements = forStatements(); + node = new For(init, to, step, statements); + return node; + } If if_() { lex.popFront(); @@ -430,7 +530,7 @@ class Parser Statements else_; if(token.type == TokenType.Else) { - if(lex.front().type == TokenType.NewLine) + if(!multiline && lex.front().type == TokenType.NewLine) { //3.1現在だとエラー syntaxError(); @@ -438,6 +538,7 @@ class Parser if(multiline) { else_ = multilineIfStatements(); + lex.popFront(); } else { @@ -603,6 +704,12 @@ class Parser //文字列リテラル break; + case TokenType.Minus: + //TODO:UnaryOperatorの実装 + //とりあえず0-exprを作成 + lex.popFront(); + node = new BinaryOperator(new Constant(Value(0)), TokenType.Minus, expression()); + return node; default: return node; } diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index 32f2acb..89895bc 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -30,6 +30,14 @@ enum TokenType Then, Else, Endif, + For, + Next, + Equal, + NotEqual, + Less,//< + Greater,//> + LessEqual, + GreaterEqual, } struct Token