diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index 9309360..e50b525 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -867,8 +867,18 @@ class CallBuiltinFunction : Code } override void execute(VM vm) { - Value[] arg = vm.stack[vm.stacki - argcount..vm.stacki]; - Value[] result = vm.stack[vm.stacki - argcount..vm.stacki - argcount + outcount];//雑; + Value[] arg; + Value[] result; + if(func.hasSkipArgument) + { + arg = vm.stack[vm.stacki - func.argments.length..vm.stacki]; + result = vm.stack[vm.stacki - func.argments.length..vm.stacki - func.argments.length + outcount];//雑; + } + else + { + arg = vm.stack[vm.stacki - argcount..vm.stacki]; + result = vm.stack[vm.stacki - argcount..vm.stacki - argcount + outcount];//雑; + } func.func(vm.petitcomputer, arg, result); } } diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index b197acf..769c3f5 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -11,7 +11,7 @@ import otya.smilebasic.type; import otya.smilebasic.petitcomputer; //プチコンの引数省略は特殊なので //LOCATE ,,0のように省略できる -struct DefaultValue(T) +struct DefaultValue(T, bool skippable = true) { T value; bool isDefault; @@ -29,6 +29,11 @@ struct DefaultValue(T) { isDefault = f; } + void setDefaultValue(T v) + { + if(isDefault) + value = v; + } mixin Proxy!value; } alias ValueType = otya.smilebasic.type.ValueType; @@ -36,17 +41,24 @@ struct BuiltinFunctionArgument { ValueType argType; bool optionalArg; + bool skipArg; } class BuiltinFunction { BuiltinFunctionArgument[] argments; ValueType result; void function(PetitComputer, Value[], Value[]) func; - this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func) + int startskip; + this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func, int startskip) { this.argments = argments; this.result = result; this.func = func; + this.startskip = startskip; + } + bool hasSkipArgument() + { + return this.startskip != this.argments.length; } import std.math; /* @@ -56,8 +68,21 @@ class BuiltinFunction }*/ static double function(double) ABS = &abs!double; //static ABS = function double(double x) => abs(this.result == ValueType.Double ? 1 : 0); - static void LOCATE(PetitComputer p, DefaultValue!int x, DefaultValue!int y, DefaultValue!int z) + static void LOCATE(PetitComputer p, DefaultValue!int x, DefaultValue!int y, DefaultValue!(int, false) z) { + x.setDefaultValue(p.CSRX); + y.setDefaultValue(p.CSRY); + z.setDefaultValue(p.CSRZ); + p.CSRX = cast(int)x; + p.CSRY = cast(int)y; + p.CSRZ = cast(int)z; + } + static void COLOR(PetitComputer p, DefaultValue!int fore, DefaultValue!(int, false) back) + { + fore.setDefaultValue(p.consoleForeColor); + back.setDefaultValue(p.consoleBackColor); + p.consoleForeColor = cast(int)fore; + p.consoleBackColor = cast(int)back; } //alias void function(PetitComputer, Value[], Value[]) BuiltinFunc; static BuiltinFunction[wstring] builtinFunctions; @@ -71,7 +96,8 @@ class BuiltinFunction builtinFunctions[name] = new BuiltinFunction( GetFunctionParamType!(BuiltinFunction, name), GetFunctionReturnType!(BuiltinFunction, name), - mixin(AddFunc!(BuiltinFunction, name)) + mixin(AddFunc!(BuiltinFunction, name)), + GetStartSkip!(BuiltinFunction, name), ); writeln(AddFunc!(BuiltinFunction, name)); } @@ -79,6 +105,25 @@ class BuiltinFunction } } +template GetStartSkip(T, string N) +{ + private template SkipSkip(int I, P...) + { + static if(P.length <= I) + { + enum SkipSkip = I - is(P[0] == PetitComputer); + } + else static if(is(P[I] == DefaultValue!(int, false))) + { + enum SkipSkip = I - is(P[0] : PetitComputer); + } + else + { + enum SkipSkip = SkipSkip!(I + 1, P); + } + } + enum GetStartSkip = SkipSkip!(0, ParameterTypeTuple!(__traits(getMember, T, N))); +} template GetFunctionReturnType(T, string N) { static if(is(ReturnType!(__traits(getMember, T, N)) == double)) @@ -100,12 +145,12 @@ template AddFunc(T, string N) static if(is(ReturnType!(__traits(getMember, T, N)) == double)) { const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}ret[0] = Value(" ~ N ~ "(" ~ - AddFuncArg!(0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}"; + AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}"; } else static if(is(ReturnType!(__traits(getMember, T, N)) == void)) { - const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}" ~ N ~ "(" ~ - AddFuncArg!(0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}"; + const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 0){throw new IllegalFunctionCall();}" ~ N ~ "(" ~ + AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}"; } else { @@ -120,6 +165,13 @@ DefaultValue!int fromIntToDefault(Value v) else return DefaultValue!int(true); } +DefaultValue!(int, false) fromIntToSkip(Value v) +{ + if(v.isNumber) + return DefaultValue!(int, false)(v.castInteger()); + else + return DefaultValue!(int, false)(true); +} template GetFunctionParamType(T, string N) { enum GetFunctionParamType = mixin("[" ~ Array!(ParameterTypeTuple!(__traits(getMember, T, N))) ~ "]"); @@ -137,6 +189,10 @@ template GetFunctionParamType(T, string N) { const string arg = "ValueType.Integer, true"; } + else static if(is(P[0] == DefaultValue!(int, false))) + { + const string arg = "ValueType.Integer, true"; + } else static if(is(P[0] == PetitComputer)) { enum Array = Array!(P[1..$]); @@ -151,12 +207,13 @@ template GetFunctionParamType(T, string N) } } } -template AddFuncArg(int N, int M, P...) +template AddFuncArg(int L, int N, int M, P...) { + enum I = L - N; static if(is(P[0] == double)) { enum add = 1; - const string arg = "arg[" ~ N.to!string ~ "].castDouble"; + const string arg = "arg[" ~ I.to!string ~ "].castDouble"; } else static if(is(P[0] == PetitComputer)) { @@ -166,12 +223,17 @@ template AddFuncArg(int N, int M, P...) else static if(is(P[0] == int)) { enum add = 1; - const string arg = "arg[" ~ N.to!string ~ "].castInteger"; + const string arg = "arg[" ~ I.to!string ~ "].castInteger"; } else static if(is(P[0] == DefaultValue!int)) { enum add = 1; - const string arg = "fromIntToDefault(arg[" ~ N.to!string ~ "])"; + const string arg = "fromIntToDefault(arg[" ~ I.to!string ~ "])"; + } + else static if(is(P[0] == DefaultValue!(int, false))) + { + enum add = 1; + const string arg = "fromIntToSkip(arg[" ~ I.to!string ~ "])"; } else { @@ -185,6 +247,6 @@ template AddFuncArg(int N, int M, P...) } else { - const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(N + add, M + 1, P[1..$]); + const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, P[1..$]); } } diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index f730e85..a8868cc 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -331,11 +331,19 @@ class Compiler case NodeType.CallFunction: { auto func = cast(CallFunction)exp; + auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); + if(bfun) + { + auto k = bfun.argments.length - func.args.length; + foreach(l;0..k) + { + genCodeImm(Value(ValueType.Void)); + } + } foreach_reverse(Expression i ; func.args) { compileExpression(i, sc); } - auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); if(bfun) { genCode(new CallBuiltinFunction(bfun, func.args.length, 1)); @@ -602,11 +610,19 @@ class Compiler case NodeType.CallFunctionStatement: { auto func = cast(CallFunctionStatement)i; + auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); + if(bfun) + { + auto k = bfun.argments.length - func.args.length; + foreach(l;0..k) + { + genCodeImm(Value(ValueType.Void)); + } + } foreach_reverse(Expression j ; func.args) { compileExpression(j, s); } - auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); if(bfun) { genCode(new CallBuiltinFunction(bfun, func.args.length, func.outVariable.length)); diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index 674e44a..03cc592 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -39,7 +39,36 @@ class PetitComputer int fontHeight; int consoleWidth; int consoleHeight; - wchar[][] console; + int[] consoleColor = + [ + 0x00000000, + 0xFF000000, + 0xFF7F0000, + 0xFFFF0000, + 0xFF007F00, + 0xFF00FF00, + 0xFF7F7F00, + 0xFFFFFF00, + 0xFF00007F, + 0xFF0000FF, + 0xFF7F007F, + 0xFFFF00FF, + 0xFF007F7F, + 0xFF00FFFF, + 0xFF7F7F7F, + 0xFFFFFFFF, + ]; + struct ConsoleCharacter + { + wchar charater; + int foreColor; + int backColor; + } + SDL_Color PetitColor(byte r, byte g, byte b, byte a) + { + return SDL_Color(r >> 5 << 5, g >> 5 << 5, b >> 5 << 5, a == 255 ? 255 : 0); + } + ConsoleCharacter[][] console; GraphicPage[] grp; GraphicPage GRPF; //PNG画像から透過色のpixelを指定して透過しGRPを作る @@ -158,12 +187,15 @@ class PetitComputer fontHeight = 8; consoleWidth = screenWidth / fontWidth; consoleHeight = screenHeight / fontHeight; - console = new wchar[][consoleHeight]; + console = new ConsoleCharacter[][consoleHeight]; + consoleForeColor = 15;//#T_WHITE for(int i = 0; i < console.length; i++) { - console[i] = new wchar[consoleWidth]; + console[i] = new ConsoleCharacter[consoleWidth]; + console[i][] = ConsoleCharacter(0, consoleForeColor, consoleBackColor); + /* for(int j = 0; j < console[i].length; j++) - console[i][j] = '\0'; + console[i][j] = '\0';*/ } } SDL_Renderer* renderer; @@ -177,15 +209,26 @@ class PetitComputer renderer = SDL_CreateRenderer(window, -1, 0); GRPF.createTexture(renderer); //とりあえず - auto parser = new Parser(/*readText("FIZZBUZZ.TXT").to!wstring*/" + auto parser = new Parser(/*readText("FIZZBUZZ.TXT").to!wstring*//*" ?ABS(-1) +LOCATE 0,10 +COLOR 5 FOR I=0 TO 10 ?I;\"!\",\"=\",FACT(I) NEXT DEF FACT(N) IF N<=1 THEN RETURN 1 RETURN N*FACT(N-1) -END"); +END"*/ +`CLS : CL=0 : Z=0 +WHILE 1 + INC Z : IF Z>200 THEN Z=0 + FOR I=0 TO 15 + LOCATE 9,4+I,Z : COLOR (CL+I) MOD 16 + PRINT "★ 梅雨で雨が多い季節ですね ★" + NEXT + CL=(CL+1) MOD 16 : VSYNC 2 +WEND`); auto vm = parser.compile(); bool running = true; vm.init(this); @@ -209,7 +252,7 @@ END"); catch { } - }/* + } catch(Throwable t) { running = false; @@ -220,7 +263,7 @@ END"); catch { } - }*/ + } elapse = SDL_GetTicks() - startTicks; } while(elapse <= 1000 / 60); SDL_Event event; @@ -248,13 +291,20 @@ END"); int CSRX; int CSRY; int CSRZ; + int consoleForeColor, consoleBackColor; void renderConsole() { for(int y = 0; y < consoleHeight; y++) for(int x = 0; x < consoleWidth; x++) { SDL_Rect rect = SDL_Rect(x * 8, y * 8, 8, 8); - SDL_RenderCopy(renderer, GRPF.texture, &fontTable[console[y][x]], &rect); + auto back = consoleColor[console[y][x].backColor]; + SDL_SetRenderDrawColor(renderer, back >> 16 & 0xFF, back >> 8 & 0xFF, back & 0xFF, back >> 24 & 0xFF); + SDL_RenderFillRect(renderer, &rect); + auto fore = consoleColor[console[y][x].foreColor]; + SDL_SetTextureColorMod(GRPF.texture, fore >> 16 & 0xFF, fore >> 8 & 0xFF, fore & 0xFF); + SDL_SetTextureAlphaMod(GRPF.texture, fore >> 24 & 0xFF); + SDL_RenderCopy(renderer, GRPF.texture, &fontTable[console[y][x].charater], &rect); } } void printConsole(T...)(T args) @@ -274,7 +324,9 @@ END"); } if(c != '\r' && c != '\n') { - console[CSRY][CSRX] = c; + console[CSRY][CSRX].charater = c; + console[CSRY][CSRX].foreColor = consoleForeColor; + console[CSRY][CSRX].backColor = consoleBackColor; } CSRX++; if(CSRX >= consoleWidth || c == '\n' || c == '\r') @@ -290,8 +342,7 @@ END"); console[i] = console[i + 1]; } console[consoleHeight - 1] = tmp; - for(int j = 0; j < tmp.length; j++) - tmp[j] = '\0'; + tmp[] = ConsoleCharacter(0, consoleForeColor, consoleBackColor); assert(console[0] != console[2]); CSRY = consoleHeight - 1; }