From c71e84a7fc25ef031381b8fc254192db4ea54303 Mon Sep 17 00:00:00 2001 From: otya128 Date: Sun, 14 Jun 2015 11:13:19 +0900 Subject: [PATCH] =?UTF-8?q?OUT=E9=96=A2=E6=95=B0=E3=82=92=E5=AE=9F?= =?UTF-8?q?=E8=A3=85,=20=E8=AD=98=E5=88=A5=E5=AD=90=E3=81=AB=E6=95=B0?= =?UTF-8?q?=E5=AD=97=E3=81=A8=5F=E3=82=92=E8=AA=8D=E8=AD=98=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SMILEBASIC/VM.d | 20 ++++++++++ SMILEBASIC/compiler.d | 48 +++++++++++++++++++++-- SMILEBASIC/main.d | 19 +++++++++ SMILEBASIC/node.d | 20 ++++++++++ SMILEBASIC/parser.d | 91 ++++++++++++++++++++++++++++++++++++++----- SMILEBASIC/token.d | 1 + 6 files changed, 187 insertions(+), 12 deletions(-) diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index cd3c054..5f9747f 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -770,6 +770,14 @@ class ReturnFunction : Code { vm.push(retexpr); } + else + { + //OUTの実装 + for(int i = 0; i < func.outArgCount; i++) + { + vm.push(vm.stack[vm.bp + i + 2]); + } + } vm.pc = pc.integerValue; vm.bp = bp.integerValue; } @@ -778,10 +786,18 @@ class CallFunctionCode : Code { wstring name; int argCount; + int outArgCount; this(wstring name, int argCount) { this.name = name; this.argCount = argCount; + this.outArgCount = 1; + } + this(wstring name, int argCount, int outArgCount) + { + this.name = name; + this.argCount = argCount; + this.outArgCount = outArgCount; } override void execute(VM vm) { @@ -794,6 +810,10 @@ class CallFunctionCode : Code { throw new IllegalFunctionCall(); } + if(func.outArgCount != this.outArgCount) + { + throw new IllegalFunctionCall(); + } //TODO:args auto bp = vm.stacki; vm.push(Value(vm.bp)); diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 6b0b0ad..5a577a5 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -34,6 +34,7 @@ class Function VMVariable[wstring] variable; int[wstring] label; bool returnExpr; + int outArgCount; this(int address, wstring name, bool returnExpr, int argCount) { this.address = address; @@ -41,6 +42,10 @@ class Function this.returnExpr = returnExpr; this.argCount = argCount; this.variableIndex = 1;//0,bp,1,pc + if(returnExpr) + { + outArgCount = 1; + } } int getLocalVarIndex(wstring name, Compiler c) { @@ -72,6 +77,20 @@ class Function } return var; } + int defineLocalVarIndexVoid(wstring name, Compiler c) + { + int var = this.variable.get(name, VMVariable()).index; + if(var == 0) + { + this.variable[name] = VMVariable(var = ++variableIndex, ValueType.Void); + } + else + { + //error:二重定義 + throw new DuplicateVariable(); + } + return var; + } int defineArgumentIndex(wstring name, Compiler c) { int var = this.variable.get(name, VMVariable()).index; @@ -224,7 +243,7 @@ class Compiler { if(sc.func) { - return sc.func.defineLocalVarIndex(name, this); + return sc.func.defineLocalVarIndexVoid(name, this); } int global = this.global.get(name, VMVariable()).index; if(global == 0) @@ -447,7 +466,16 @@ class Compiler { func.defineArgumentIndex(arg, this); } + foreach(wstring arg; node.outArguments) + { + func.defineLocalVarIndexVoid(arg, this); + } + if(!func.returnExpr) + func.outArgCount = node.outArguments.length; compileStatements(node.functionBody, sc); + if(func.returnExpr) + genCodeImm(Value(ValueType.Void)); + genCode(new ReturnFunction(func)); skip.address = this.code.length; this.functions[func.name] = func; } @@ -528,8 +556,7 @@ class Compiler } else { - //TODO:実装中 - throw new SyntaxError(); + genCode(new ReturnFunction(s.func)); } } } @@ -564,6 +591,21 @@ class Compiler genCode(new PopArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length, !(s.func is null))); } break; + case NodeType.CallFunctionStatement: + { + auto func = cast(CallFunctionStatement)i; + foreach_reverse(Expression j ; func.args) + { + compileExpression(j, s); + } + genCode(new CallFunctionCode(func.name, func.args.length, func.outVariable.length)); + //TODO:OUT + foreach_reverse(wstring var; func.outVariable) + { + genCodePopVar(var, s); + } + } + break; default: stderr.writeln("Compile:NotImpl ", i.type); } diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 173d877..4b90b2b 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -61,6 +61,12 @@ V[0,1]=12 GOSUB @A ?A() ?B(1,2,3) +FOR I=0 TO 10 + ?I;\"!\",\"=\",FACT(I) +NEXT +TEST \"HELLO\",\",\",\"WORLD\" +TEST2 6,7,8 OUT K,L,M +?K,L,M END @A ?\"SUBROUTINE TEST\" @@ -75,6 +81,19 @@ DEF B(A,B[],C) ?LOCAL RETURN -1 END +DEF FACT(N) + IF N<=1 THEN RETURN 1 + RETURN N*FACT(N-1) +END +DEF TEST A,B,C + ?\"TEST\",A,B,C +END +DEF TEST2 A,B,C OUT D,E,F + ?\"TEST\",A,B,C + D=A + E=B + F=C +END "); 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 7ad6c4a..e0864fa 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -388,3 +388,23 @@ class DefineFunction : Statement this.outArguments ~= name; } } +class CallFunctionStatement : Statement +{ + wstring name; + Expression[] args; + wstring[] outVariable; + this(wstring n) + { + this.type = NodeType.CallFunctionStatement; + this.name = n; + args = new Expression[0]; + } + void addArg(Expression arg) + { + args ~= arg; + } + void addOut(wstring var) + { + outVariable ~= var; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index d672ef8..0b8439d 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -59,6 +59,7 @@ class Lexical reserved["VAR"] = TokenType.Var; reserved["DIM"] = TokenType.Var; reserved["DEF"] = TokenType.Def; + reserved["OUT"] = TokenType.Out; reserved.rehash(); line = 1; } @@ -104,7 +105,7 @@ class Lexical for(;i < code.length;i++) { c = code[i]; - if(!c.isAlpha()) + if(!c.isAlpha() && !c.isDigit() && c != '_') { break; } @@ -420,7 +421,7 @@ class Parser } return statements; } - bool isFunc = false; + bool isFuncReturnExpr = false; wstring getFunctionArgument() { auto token = lex.front(); @@ -490,15 +491,49 @@ class Parser } else { + //MEMO:引数に[]を付けようが扱いは同一 + while(true) + { + wstring arg = getFunctionArgument(); + if(arg.length == 0) + { + return null; + } + node.addArgument(arg); + token = lex.front(); + if(token.type == TokenType.Comma) + { + lex.popFront(); + continue; + } + break; + } + if(token.type == TokenType.Out) + { + lex.popFront(); + while(true) + { + wstring arg = getFunctionArgument(); + if(arg.length == 0) + { + return null; + } + node.addOutArgument(arg); + token = lex.front(); + if(token.type == TokenType.Comma) + { + lex.popFront(); + continue; + } + break; + } + } node.returnExpr = false; //void関数にRETURN核とsyntaxerror - writeln("NOTIMPL:DEF VOID"); - syntaxError(); - return null; } - isFunc = true;//面倒くさい + isFuncReturnExpr = node.returnExpr;//面倒くさい node.functionBody = functionStatements(); - isFunc = false; + isFuncReturnExpr = false; return node; } Statements functionStatements() @@ -601,6 +636,45 @@ class Parser return node; } //命令呼び出し + auto func = new CallFunctionStatement(name); + node = func; + while(true) + { + token = lex.front(); + + if(token.type == TokenType.Comma) + { + func.addArg(new VoidExpression()); + lex.popFront(); + token = lex.front(); + } + else + func.addArg(expression()); + if(lex.front().type != TokenType.Comma) break; + lex.popFront(); + } + if(lex.front().type == TokenType.Out) + { + lex.popFront(); + while(true) + { + token = lex.front(); + if(token.type != TokenType.Iden) + { + return null; + } + wstring arg = token.value.stringValue; + func.addOut(arg); + lex.popFront(); + token = lex.front(); + if(token.type == TokenType.Comma) + { + lex.popFront(); + continue; + } + break; + } + } } break; case TokenType.Colon: @@ -639,10 +713,9 @@ class Parser break; case TokenType.Return: lex.popFront(); - if(isFunc) + if(isFuncReturnExpr) { node = new Return(expression()); - lex.popFront(); } else { diff --git a/SMILEBASIC/token.d b/SMILEBASIC/token.d index c41b04e..4f0ec70 100644 --- a/SMILEBASIC/token.d +++ b/SMILEBASIC/token.d @@ -53,6 +53,7 @@ enum TokenType LBracket,//[ RBracket,//] Def, + Out, } struct Token