diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 6d0b255..4c03b81 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -85,6 +85,22 @@ struct Callback return !func.isDead; return false; } + void opCall(VM vm) + { + if (!isCallable) + return; + if (type == CallbackType.label) + { + vm.pushBackTrace(""); + vm.pushpc; + vm.setCurrentSlot(slot.index); + vm.pc = label - 1; + } + if (type == CallbackType.function_) + { + vm.call(func, 0, 0); + } + } } class VM @@ -501,6 +517,42 @@ class VM result.label = label; return result; } + void call(Function func, int argCount, int outArgCount) + { + alias vm = this; + if(func.argCount != argCount) + { + throw new IllegalFunctionCall(func.name.to!string); + } + if(func.outArgCount != outArgCount) + { + throw new IllegalFunctionCall(func.name.to!string); + } + vm.pushBackTrace(func.name); + //TODO:args + auto bp = vm.stacki; + vm.push(Value(vm.currentFunction)); + vm.currentFunction = func; + vm.push(Value(vm.currentData)); + vm.currentData.index = 0; + vm.currentData.table = func.scope_.data; + vm.push(Value(vm.bp)); + vm.pushpc;//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); + } + } + if (func.isCommon) + { + vm.setCurrentSlot(func.slot.index); + } + } } enum CodeType { @@ -1612,38 +1664,7 @@ class CallFunctionCode : Code { resolve(vm); } - if(func.argCount != this.argCount) - { - throw new IllegalFunctionCall(name.to!string); - } - if(func.outArgCount != this.outArgCount) - { - throw new IllegalFunctionCall(name.to!string); - } - vm.pushBackTrace(name); - //TODO:args - auto bp = vm.stacki; - vm.push(Value(vm.currentFunction)); - vm.currentFunction = func; - vm.push(Value(vm.currentData)); - vm.currentData.index = 0; - vm.currentData.table = func.scope_.data; - vm.push(Value(vm.bp)); - vm.pushpc;//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); - } - } - if (func.isCommon) - { - vm.setCurrentSlot(func.slot.index); - } + vm.call(func, this.argCount, this.outArgCount); } override string toString(VM vm) { @@ -1690,34 +1711,7 @@ class CallFunctionS : Code } void callFunc(Function func, VM vm) { - if(func.argCount != this.argCount) - { - throw new IllegalFunctionCall(func.name.to!string); - } - if(func.outArgCount != this.outArgCount) - { - throw new IllegalFunctionCall(func.name.to!string); - } - //TODO:args - auto bp = vm.stacki; - vm.push(Value(vm.currentFunction)); - vm.currentFunction = func; - vm.push(Value(vm.currentData)); - vm.currentData.index = 0; - vm.currentData.table = func.scope_.data; - vm.push(Value(vm.bp)); - vm.pushpc; - 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); - } - } - vm.setCurrentSlot(func.slot.index); + vm.call(func, argCount, outArgCount); } override void execute(VM vm) { @@ -1759,7 +1753,6 @@ class CallFunctionS : Code callBuintinFunc(bfunc, vm); return; } - vm.pushBackTrace(name.name); callFunc(func, vm); } override string toString(VM vm) @@ -2683,3 +2676,70 @@ class ConvertBool : Code top.type = ValueType.Integer; } } + +/+ +SPFUNC 0,@A +FOR I=1TO 511 +SPFUNC I,@B +NEXT +CALL SPRITE +END +@A +?"BEFORE CALL BG",CALLIDX +CALL BG +?"AFTER CALL BG",CALLIDX +RETUERN +@B +?CALLIDX +RETURN + +RESULT +BEFORE CALL BG 0 +AFTER CALL BG 4 +=>SPFUNC 1~511 is not called ++/ +class InitCallback : Code +{ + override void execute(VM vm) + { + vm.petitcomputer.callidx = -1; + vm.petitcomputer.callback = true; + } +} + +class CallSprite : Code +{ + override void execute(VM vm) + { + vm.petitcomputer.callidx++; + if (!vm.petitcomputer.callback) + { + return; + } + if (!vm.petitcomputer.sprite.isValidSpriteId(vm.petitcomputer.callidx)) + { + vm.petitcomputer.callback = false; + return; + } + auto callback = vm.petitcomputer.sprite.getCallback(vm.petitcomputer.callidx); + vm.pc--; + if (!callback.isCallable) + { + return; + } + callback(vm); + } +} + +class CallBG : Code +{ + override void execute(VM vm) + { + if (!vm.petitcomputer.callback) + { + vm.petitcomputer.callidx++; + return; + } + vm.petitcomputer.callidx++; + } +} diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index d6ac11a..d1c849e 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -227,6 +227,7 @@ class Compiler addSystemVariable("HARDWARE", new Hardware()); addSystemVariable("MILLISEC", new MilliSecond()); addSystemVariable("PRGSLOT", new ProgramSlot()); + addSystemVariable("CALLIDX", new CallIndex()); } void addSystemVariable(wstring name, SystemVariable var) { @@ -970,6 +971,16 @@ class Compiler genCode(new otya.smilebasic.vm.Linput); compilePopVar(linput.expression, sc); } + void compileCallSprite(otya.smilebasic.node.CallSprite call, Scope sc) + { + genCode(new InitCallback); + genCode(new otya.smilebasic.vm.CallSprite); + } + void compileCallBG(otya.smilebasic.node.CallBG call, Scope sc) + { + genCode(new InitCallback); + genCode(new otya.smilebasic.vm.CallBG); + } void compileStatement(Statement i, Scope s) { switch(i.type) @@ -1247,6 +1258,12 @@ class Compiler case NodeType.Linput: compileLinput(cast(otya.smilebasic.node.Linput)i, s); break; + case NodeType.CallSprite: + compileCallSprite(cast(otya.smilebasic.node.CallSprite)i, s); + break; + case NodeType.CallBG: + compileCallBG(cast(otya.smilebasic.node.CallBG)i, s); + break; default: stderr.writeln("Compile:NotImpl ", i.type); } diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index fe2b460..57e6306 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -51,6 +51,8 @@ enum NodeType Exec, Use, Linput, + CallSprite, + CallBG, } abstract class Node { @@ -697,3 +699,19 @@ class Linput : Statement this.expression = expr; } } +class CallSprite : Statement +{ + this(SourceLocation loc) + { + super.location = loc; + this.type = NodeType.CallSprite; + } +} +class CallBG : Statement +{ + this(SourceLocation loc) + { + super.location = loc; + this.type = NodeType.CallBG; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 4ef2759..e286e6f 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -939,6 +939,23 @@ class Parser } } lex.popFront(); + if (token.type == TokenType.Call) + { + if (lex.front.type == TokenType.Iden) + { + auto arg = std.uni.toUpper(lex.front.value.castString); + if (arg == "SPRITE") + { + node = new CallSprite(lex.location); + break; + } + if (arg == "BG") + { + node = new CallBG(lex.location); + break; + } + } + } //命令呼び出し auto func = new CallFunctionStatement(name, lex.location); node = func; diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index b66496e..616e157 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -1695,6 +1695,9 @@ class PetitComputer SDL_SetClipboardText(ws.to!string.toStringz); } + bool callback; + int callidx = 0; + //プチコン内部表現はRGB5_A1 static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a) { diff --git a/SMILEBASIC/sprite.d b/SMILEBASIC/sprite.d index 629cf4d..b93c316 100644 --- a/SMILEBASIC/sprite.d +++ b/SMILEBASIC/sprite.d @@ -1191,4 +1191,8 @@ class Sprite id = spid(id); sprites[id].callback = callback; } + Callback getCallback(int id) + { + return sprites[spid(id)].callback; + } } diff --git a/SMILEBASIC/systemvariable.d b/SMILEBASIC/systemvariable.d index 7159014..2064771 100644 --- a/SMILEBASIC/systemvariable.d +++ b/SMILEBASIC/systemvariable.d @@ -10,6 +10,9 @@ class SystemVariable @property void value(Value value) { + //v3.3.2 + //TIME$=1,TIME$="1"=>Type mismatch(runtime) + //MAINCNT=1,MAINCNT="1"=>Syntax error(runtime) throw new TypeMismatch(); } } @@ -139,3 +142,10 @@ class ProgramSlot : SystemVariable return Value(vm.petitcomputer.program.currentSlot); } } +class CallIndex : SystemVariable +{ + @property override Value value() + { + return Value(vm.petitcomputer.callidx); + } +}