From b8a063f0a5975af2d90f622a64d778ccc266e6e2 Mon Sep 17 00:00:00 2001 From: otya128 Date: Sat, 13 Jun 2015 21:35:28 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=82=AB=E3=83=AB=E5=A4=89?= =?UTF-8?q?=E6=95=B0=E3=81=AE=E5=8F=82=E7=85=A7,=E5=AE=9A=E7=BE=A9?= =?UTF-8?q?=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 | 129 +++++++++++++++++++++++--------- SMILEBASIC/compiler.d | 169 +++++++++++++++++++++++++++++++----------- SMILEBASIC/main.d | 4 +- 3 files changed, 223 insertions(+), 79 deletions(-) diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 2a818f0..cd3c054 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -7,6 +7,16 @@ import std.uni; import std.utf; import std.conv; import std.stdio; +struct VMVariable +{ + int index; + ValueType type; + this(int index, ValueType type) + { + this.index = index; + this.type = type; + } +} class VM { Code[] code; @@ -14,33 +24,18 @@ class VM int pc; Value[] stack; Value[] global; - int[wstring] globalTable; + VMVariable[wstring] globalTable; Function[wstring] functions; int bp; - ValueType getType(wstring name) - { - wchar s = name[name.length - 1]; - switch(s) - { - case '$': - return ValueType.String; - case '#': - return ValueType.Double; - case '%': - return ValueType.Integer; - default: - return ValueType.Double;//DEFINT時 - } - } - this(Code[] code, int len, int[wstring] globalTable, Function[wstring] functions) + this(Code[] code, int len, VMVariable[wstring] globalTable, Function[wstring] functions) { this.code = code; this.stack = new Value[16384]; this.global = new Value[len]; this.globalTable = globalTable; - foreach(wstring k, int v ; globalTable) + foreach(wstring k, VMVariable v ; globalTable) { - this.global[v] = Value(getType(k)); + this.global[v.index] = Value(v.type); } this.functions = functions; } @@ -79,7 +74,7 @@ class VM } Value testGetGlobalVariable(wstring name) { - return global[globalTable[name]]; + return global[globalTable[name].index]; } void end() { @@ -90,12 +85,14 @@ enum CodeType { Push, PushG, + PushL, Operate, Return, Goto, Gosub, Print, PopG, + PopL, GotoS, GotoFalse, GotoTrue, @@ -193,7 +190,7 @@ class PopG : Code vm.global[var] = Value(cast(int)v.doubleValue); return; } - if(v.type == ValueType.Void) + if(g.type == ValueType.Void) { vm.global[var] = v; return; @@ -205,6 +202,54 @@ class PopG : Code vm.global[var] = v; } } +class PushL : Code +{ + int var; + this(int var) + { + this.type = CodeType.PushL; + this.var = var; + } + override void execute(VM vm) + { + vm.push(vm.stack[vm.bp + var]); + } +} +class PopL : Code +{ + int var; + this(int var) + { + this.type = CodeType.PopL; + this.var = var; + } + override void execute(VM vm) + { + Value v; + Value g = vm.stack[vm.bp + var]; + vm.pop(v); + if(v.type == ValueType.Integer && g.type == ValueType.Double) + { + vm.stack[vm.bp + var] = Value(cast(double)v.integerValue); + return; + } + if(g.type == ValueType.Integer && v.type == ValueType.Double) + { + vm.stack[vm.bp + var] = Value(cast(int)v.doubleValue); + return; + } + if(g.type == ValueType.Void) + { + vm.stack[vm.bp + var] = v; + return; + } + if(v.type != g.type) + { + throw new TypeMismatch(); + } + vm.stack[vm.bp + var] = v; + } +} class Operate : Code { TokenType operator; @@ -518,15 +563,13 @@ class EndVM : Code class NewArray : Code { ValueType type; - int index; int size; int[] dim; - this(ValueType type, int size, int index) + this(ValueType type, int size) { dim = new int[size]; this.size = size; this.type = type; - this.index = index; } override void execute(VM vm) { @@ -546,24 +589,26 @@ class NewArray : Code } throw new TypeMismatch(); } + Value array; switch(type) { case ValueType.Integer: - vm.global[index].type = ValueType.IntegerArray; - vm.global[index].integerArray = new Array!int(dim); + array.type = ValueType.IntegerArray; + array.integerArray = new Array!int(dim); break; case ValueType.Double: - vm.global[index].type = ValueType.DoubleArray; - vm.global[index].doubleArray = new Array!double(dim); + array.type = ValueType.DoubleArray; + array.doubleArray = new Array!double(dim); break; case ValueType.String: - vm.global[index].type = ValueType.StringArray; - vm.global[index].stringArray = new Array!wstring(dim); + array.type = ValueType.StringArray; + array.stringArray = new Array!wstring(dim); break; default: throw new TypeMismatch(); break; } + vm.push(array); } } class PushArray : Code @@ -626,18 +671,28 @@ class PushArray : Code throw new TypeMismatch(); } } -class PopGArray : Code +class PopArray : Code { int var; int dim; - this(int var, int dim) + bool local; + this(int var, int dim, bool local) { this.var = var; this.dim = dim; + this.local = local; } override void execute(VM vm) { - Value array = vm.global[var]; + Value array; + if(local) + { + array = vm.stack[vm.bp + var]; + } + else + { + array = vm.global[var]; + } if(!array.isArray) { throw new TypeMismatch(); @@ -745,5 +800,13 @@ class CallFunctionCode : Code vm.push(Value(vm.pc)); vm.bp = bp; vm.pc = func.address - 1; + vm.stacki += func.variableIndex - 1; + foreach(wstring k, VMVariable v ; func.variable) + { + if(v.index > 0) + { + vm.stack[bp + v.index] = Value(v.type); + } + } } } diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 72417b9..6b0b0ad 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -13,10 +13,11 @@ class Scope this() { } - this(GotoAddr breakAddr, GotoAddr continueAddr) + this(GotoAddr breakAddr, GotoAddr continueAddr, Scope parent) { this.breakAddr = breakAddr; this.continueAddr = continueAddr; + this.func = parent.func; } this(Function func) { @@ -30,7 +31,7 @@ class Function int argCount; int argumentIndex; int variableIndex; - int[wstring] variable; + VMVariable[wstring] variable; int[wstring] label; bool returnExpr; this(int address, wstring name, bool returnExpr, int argCount) @@ -41,23 +42,28 @@ class Function this.argCount = argCount; this.variableIndex = 1;//0,bp,1,pc } - int getLocalVarIndex(wstring name) + int getLocalVarIndex(wstring name, Compiler c) { - int var = this.variable.get(name, 0); + int var = this.variable.get(name, VMVariable()).index; if(var == 0) { //local変数をあたる //それでもだめならOPTION STRICTならエラー - this.variable[name] = var = ++variableIndex; + this.variable[name] = VMVariable(var = ++variableIndex, c.getType(name)); } return var; } - int defineLocalVarIndex(wstring name) + int hasLocalVarIndex(wstring name) { - int var = this.variable.get(name, 0); + int var = this.variable.get(name, VMVariable()).index; + return var; + } + int defineLocalVarIndex(wstring name, Compiler c) + { + int var = this.variable.get(name, VMVariable()).index; if(var == 0) { - this.variable[name] = var = ++variableIndex; + this.variable[name] = VMVariable(var = ++variableIndex, c.getType(name)); } else { @@ -66,12 +72,12 @@ class Function } return var; } - int defineArgumentIndex(wstring name) + int defineArgumentIndex(wstring name, Compiler c) { - int var = this.variable.get(name, 0); + int var = this.variable.get(name, VMVariable()).index; if(var == 0) { - this.variable[name] = var = --argumentIndex; + this.variable[name] = VMVariable(var = --argumentIndex, c.getType(name)); } else { @@ -106,7 +112,7 @@ class Compiler } Code[] code; - int[wstring] global; + VMVariable[wstring] global; int[wstring] globalLabel; Function[wstring] functions; int globalIndex = 0; @@ -126,6 +132,36 @@ class Compiler { code ~= new PopG(ind); } + void genCodePushVar(wstring name, Scope sc) + { + auto global = hasGlobalVarIndex(name); + if(global) + { + code ~= new PushG(global); + return; + } + if(sc.func) + { + code ~= new PushL(sc.func.getLocalVarIndex(name, this)); + return; + } + code ~= new PushG(getGlobalVarIndex(name)); + } + void genCodePopVar(wstring name, Scope sc) + { + auto global = hasGlobalVarIndex(name); + if(global) + { + code ~= new PopG(global); + return; + } + if(sc.func) + { + code ~= new PopL(sc.func.getLocalVarIndex(name, this)); + return; + } + code ~= new PopG(getGlobalVarIndex(name)); + } void genCodeOP(TokenType op) { code ~= new Operate(op); @@ -164,10 +200,36 @@ class Compiler } int defineGlobalVarIndex(wstring name) { - int global = this.global.get(name, 0); + int global = this.global.get(name, VMVariable()).index; if(global == 0) { - this.global[name] = global = ++globalIndex; + this.global[name] = VMVariable(global = ++globalIndex, getType(name)); + } + else + { + //error:二重定義 + throw new DuplicateVariable(); + } + return global; + } + int defineVarIndex(wstring name, Scope sc) + { + if(sc.func) + { + return sc.func.defineLocalVarIndex(name, this); + } + return defineGlobalVarIndex(name); + } + int defineVarIndexVoid(wstring name, Scope sc) + { + if(sc.func) + { + return sc.func.defineLocalVarIndex(name, this); + } + int global = this.global.get(name, VMVariable()).index; + if(global == 0) + { + this.global[name] = VMVariable(global = ++globalIndex, ValueType.Void); } else { @@ -178,16 +240,32 @@ class Compiler } int getGlobalVarIndex(wstring name) { - int global = this.global.get(name, 0); + int global = this.global.get(name, VMVariable()).index; if(global == 0) { //local変数をあたる //それでもだめならOPTION STRICTならエラー - this.global[name] = global = ++globalIndex; + this.global[name] = VMVariable(global = ++globalIndex, getType(name)); } return global; } - void compileExpression(Expression exp) + int hasGlobalVarIndex(wstring name) + { + int global = this.global.get(name, VMVariable()).index; + return global; + } + int getLocalVarIndex(wstring name, Scope sc) + { + if(sc.func) + { + int global = hasGlobalVarIndex(name); + if(global) return global; + int local = sc.func.getLocalVarIndex(name, this); + return local; + } + return 0; + } + void compileExpression(Expression exp, Scope sc) { if(!exp) { @@ -202,8 +280,8 @@ class Compiler case NodeType.BinaryOperator: { auto binop = cast(BinaryOperator)exp; - compileExpression(binop.item1); - compileExpression(binop.item2); + compileExpression(binop.item1, sc); + compileExpression(binop.item2, sc); if(binop.operator == TokenType.LBracket) { IndexExpressions ie = cast(IndexExpressions)binop.item2; @@ -223,20 +301,20 @@ class Compiler case NodeType.UnaryOperator: { auto una = cast(UnaryOperator)exp; - compileExpression(una.item); + compileExpression(una.item, sc); genCodeOP(una.operator); } break; case NodeType.Variable: auto var = cast(Variable)exp; - genCodePushGlobal(getGlobalVarIndex(var.name)); + genCodePushVar(var.name, sc); break; case NodeType.CallFunction: { auto func = cast(CallFunction)exp; foreach_reverse(Expression i ; func.args) { - compileExpression(i); + compileExpression(i, sc); } genCode(new CallFunctionCode(func.name, func.args.length)); } @@ -247,7 +325,7 @@ class Compiler int count = 0; foreach_reverse(Expression i; index.expressions) { - compileExpression(i); + compileExpression(i, sc); count++; if(count >= 4) break;//念のため } @@ -260,7 +338,7 @@ class Compiler } void compileIf(If node, Scope sc) { - compileExpression(node.condition); + compileExpression(node.condition, sc); //条件式がfalseならendif or elseに飛ぶ auto else_ = genCodeGotoFalse(); compileStatements(node.then, sc); @@ -283,7 +361,7 @@ class Compiler { compileStatement(node.initExpression, s); auto forstart = code.length; - compileExpression(node.stepExpression); + compileExpression(node.stepExpression, s); genCodeImm(Value(0)); //step>=0 genCodeOP(TokenType.GreaterEqual); @@ -296,8 +374,8 @@ class Compiler //FOR I=0 TO -1 STEP -1 //-1>0 false //1>0 true - compileExpression(node.toExpression); - genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); + compileExpression(node.toExpression, s); + genCodePushVar(node.initExpression.name, s); genCodeOP(TokenType.Greater); auto breakAddr = genCodeGotoTrue(); auto forAddr = genCodeGoto(); @@ -308,19 +386,19 @@ class Compiler //0<0 false //1<0 false //0<1 true break - compileExpression(node.toExpression); - genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); + compileExpression(node.toExpression, s); + genCodePushVar(node.initExpression.name, s); genCodeOP(TokenType.Less); genCode(breakAddr); forAddr.address = code.length; - s = new Scope(new GotoAddr(-1), new GotoAddr(-1)); + s = new Scope(new GotoAddr(-1), new GotoAddr(-1), s); compileStatements(node.statements, s); s.continueAddr.address = code.length; //counterに加算する - genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); - compileExpression(node.stepExpression); + genCodePushVar(node.initExpression.name, s); + compileExpression(node.stepExpression, s); genCodeOP(TokenType.Plus); - genCodePopGlobal(getGlobalVarIndex(node.initExpression.name)); + genCodePopVar(node.initExpression.name, s); genCodeGoto(forstart); breakAddr.address = code.length; s.breakAddr.address = code.length; @@ -332,8 +410,7 @@ class Compiler if(v.type == NodeType.DefineVariable) { DefineVariable var = cast(DefineVariable)v; - //TODO:local variable - defineGlobalVarIndex(var.name); + defineVarIndex(var.name, sc); continue; } if(v.type == NodeType.DefineArray) @@ -342,12 +419,14 @@ class Compiler int siz = 0; foreach_reverse(Expression expr; var.dim.expressions) { - compileExpression(expr); + compileExpression(expr, sc); siz++; if(siz == 4) break;//4次元まで(パーサーで除去するけど万が一に備えて } - genCode(new NewArray(getType(var.name), var.dim.expressions.length, defineGlobalVarIndex(var.name))); + defineVarIndexVoid(var.name, sc); + genCode(new NewArray(getType(var.name), var.dim.expressions.length)); + genCodePopVar(var.name, sc); continue; } } @@ -366,7 +445,7 @@ class Compiler Scope sc = new Scope(func); foreach(wstring arg; node.arguments) { - func.defineArgumentIndex(arg); + func.defineArgumentIndex(arg, this); } compileStatements(node.functionBody, sc); skip.address = this.code.length; @@ -384,7 +463,7 @@ class Compiler switch(j.type) { case PrintArgumentType.Expression: - compileExpression(j.expression); + compileExpression(j.expression, s); break; case PrintArgumentType.Line: genCodeImm(Value("\n")); @@ -402,8 +481,8 @@ class Compiler case NodeType.Assign: { auto assign = cast(Assign)i; - compileExpression(assign.expression); - genCodePopGlobal(getGlobalVarIndex(assign.name)); + compileExpression(assign.expression, s); + genCodePopVar(assign.name, s); } break; case NodeType.Label: @@ -444,7 +523,7 @@ class Compiler //値を返せる関数 if(s.func.returnExpr) { - compileExpression(ret.expression); + compileExpression(ret.expression, s); genCode(new ReturnFunction(s.func)); } else @@ -480,9 +559,9 @@ class Compiler case NodeType.ArrayAssign: { auto assign = cast(ArrayAssign)i; - compileExpression(assign.assignExpression); - compileExpression(assign.indexExpression); - genCode(new PopGArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length)); + compileExpression(assign.assignExpression, s); + compileExpression(assign.indexExpression, s); + genCode(new PopArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length, !(s.func is null))); } break; default: diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 741288a..173d877 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -70,7 +70,9 @@ DEF A() RETURN 1 END DEF B(A,B[],C) - ?\"FUNCTION B\" + LOCAL=123 + ?\"FUNCTION B\",A,B,C + ?LOCAL RETURN -1 END ");