diff --git a/SMILEBASIC/TEST.txt b/SMILEBASIC/TEST.txt index 7725d8d..635b226 100644 --- a/SMILEBASIC/TEST.txt +++ b/SMILEBASIC/TEST.txt @@ -1,4 +1,5 @@ - +DIM ARRY[10] +?ARRY[0],FORMAT$("%D",100) GOSUB@A GOTO@B 'A=SIN(B) diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index dd2adca..444f832 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -129,6 +129,7 @@ enum CodeType GosubS, ReturnSubroutine, OnS, + RestoreCodeS, } abstract class Code { @@ -898,7 +899,14 @@ class CallBuiltinFunction : Code result = vm.stack[vm.stacki/* - argcount */+ 1..vm.stacki + 1/* - argcount */+ outcount];//雑; } func.func(vm.petitcomputer, arg, result); - vm.stacki -= func.argments.length;// - outcount; + if(func.variadic) + { + vm.stacki -= argcount; + } + else + { + vm.stacki -= func.argments.length;// - outcount; + } ////vm.stacki += outcount; //vm.stacki = old; for(int i = 0; i < result.length; i++) @@ -1151,6 +1159,33 @@ class ReadCode : Code } } } +class RestoreCodeS : Code +{ + wstring label; + this(wstring label) + { + this.label = label; + this.type = CodeType.RestoreCodeS; + } + override void execute(VM vm) + { + stderr.writeln("can't execute (compiler bug?)"); + } +} +class RestoreCode : Code +{ + int label; + DataTable datatable; + this(int label, DataTable datatable) + { + this.label = label; + this.datatable = datatable; + } + override void execute(VM vm) + { + datatable.dataIndex = label; + } +} class PushSystemVariable : Code { SystemVariable var; diff --git a/SMILEBASIC/builtinfunctions.d b/SMILEBASIC/builtinfunctions.d index cd84a8e..56a249d 100644 --- a/SMILEBASIC/builtinfunctions.d +++ b/SMILEBASIC/builtinfunctions.d @@ -6,6 +6,7 @@ import std.typetuple; import std.traits; import std.stdio; import std.ascii; +import std.range; import otya.smilebasic.error; import otya.smilebasic.type; import otya.smilebasic.petitcomputer; @@ -49,12 +50,15 @@ class BuiltinFunction ValueType result; void function(PetitComputer, Value[], Value[]) func; int startskip; - this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func, int startskip) + bool variadic; + this(BuiltinFunctionArgument[] argments, ValueType result, void function(PetitComputer, Value[], Value[]) func, int startskip, + bool variadic) { this.argments = argments; this.result = result; this.func = func; this.startskip = startskip; + this.variadic = variadic; } bool hasSkipArgument() { @@ -67,6 +71,7 @@ class BuiltinFunction return a < 0 ? -a : a; }*/ static double function(double) ABS = &abs!double; + static double function(double) SGN = &sgn!double; static double SIN(double arg1) { return sin(arg1); @@ -148,9 +153,21 @@ class BuiltinFunction { p.gcolor = color; } - static void BEEP(PetitComputer p, DefaultValue!(int, false) display) + static void GPRIO(PetitComputer p, int z) { } + static void BGMPLAY(PetitComputer p, int music) + { + } + static void BEEP(PetitComputer p, DefaultValue!(int, false) beep, DefaultValue!(int, false) pitch, DefaultValue!(int, false) volume, DefaultValue!(int, false) pan) + { + } + static void STICK(PetitComputer p, DefaultValue!(int, false) mp, out int x, out int y) + { + //JOYSTICK? + x = 0; + y = 0; + } static int RGB(int R, int G, int B, DefaultValue!(int, false) _) { if(!_.isDefault) @@ -189,6 +206,10 @@ class BuiltinFunction } static double VAL(wstring str) { + if(str[0..2] == "&H") + { + return str[2..$].to!int(16); + } double val = str.to!double; return val; } @@ -201,6 +222,112 @@ class BuiltinFunction //挙動未定 return str[i..i + len]; } + static void SPSET(PetitComputer p, int id, int defno) + { + p.sprite.spset(id, defno); + } + static void SPHIDE(PetitComputer p, int id) + { + p.sprite.sphide(id); + } + static void SPSHOW(PetitComputer p, int id) + { + p.sprite.spshow(id); + } + static void SPOFS(PetitComputer p, int id, int x, int y, DefaultValue!(int, false) z) + { + p.sprite.spofs(id, x, y); + } + static void SPANIM(PetitComputer p, Value[] va_args) + { + writeln("NOTIMPL:SPANIM"); + } + static void BGMSTOP(PetitComputer p) + { + writeln("NOTIMPL:BGMSTOP"); + } + static int BGMCHK(PetitComputer p) + { + writeln("NOTIMPL:BGMCHK"); + return false; + } + static int CHKCHR(PetitComputer p, int x, int y) + { + return cast(int)(p.console[y][x].character); + } + static wstring FORMAT(PetitComputer p, Value[] va_args) + { + alias retro!(Value[]) VaArgs; + auto args = retro(va_args); + auto format = args[0].castString; + import std.array : appender; + import std.format; + import std.string; + auto w = appender!wstring(); + int j = 1; + for(int i = 0; i < format.length; i++) + { + auto f = format[i]; + if(f == '%') + { + int d = indexOf(format, 'D', CaseSensitive.yes); + if(d != -1) + { + auto spec = singleSpec(format[i .. d + 1]); + spec.spec = 'd'; + formatValue(w, args[j].castInteger, spec); + j++; + i = d; + continue; + } + d = indexOf(format, 'X', CaseSensitive.yes); + if(d != -1) + { + auto spec = singleSpec(format[i .. d + 1]); + spec.spec = 'x'; + formatValue(w, args[j].castDouble, spec); + j++; + i = d; + continue; + } + d = indexOf(format, 'S', CaseSensitive.yes); + if(d != -1) + { + auto spec = singleSpec(format[i .. d + 1]); + spec.spec = 's'; + formatValue(w, args[j].castString, spec); + j++; + i = d; + continue; + } + d = indexOf(format, 'F', CaseSensitive.yes); + if(d != -1) + { + auto spec = singleSpec(format[i .. d + 1]); + spec.spec = 'f'; + formatValue(w, args[j].castDouble, spec); + j++; + i = d; + continue; + } + } + w ~= f; + } + //プチコン互換FOMA + return cast(immutable)w.data(); + } + static wstring CHR(int code) + { + return (cast(wchar)code).to!wstring; + } + static double POW(double a1, double a2) + { + return a1 ^^ a2; + } + static double SQR(double a1) + { + return sqrt(a1); + } //alias void function(PetitComputer, Value[], Value[]) BuiltinFunc; static BuiltinFunction[wstring] builtinFunctions; static this() @@ -221,6 +348,7 @@ class BuiltinFunction GetFunctionReturnType!(BuiltinFunction, name), mixin(AddFunc!(BuiltinFunction, name)), GetStartSkip!(BuiltinFunction, name), + IsVariadic!(BuiltinFunction, name), ); writeln(AddFunc!(BuiltinFunction, name)); } @@ -367,6 +495,10 @@ template GetFunctionParamType(T, string N) { const string arg = "ValueType.String, true"; } + else static if(is(P[0] == Value[])) + { + const string arg = ""; + } else static if(is(P[0] == PetitComputer)) { static if(P.length != 0) @@ -450,6 +582,10 @@ template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...) enum outadd = 0; const string arg = "fromStringToSkip(arg[" ~ I.to!string ~ "])"; } + else static if(is(P[0] == Value[])) + { + const string arg = "arg"; + } else { enum add = 1; @@ -470,28 +606,35 @@ template OutArgsInit(T, string N, int I = 0, int J = 0) { enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I]; alias param = ParameterTypeTuple!(__traits(getMember, T, N)); - static if(tuple & ParameterStorageClass.out_) + static if(!param.length) { - enum add = 1; - enum ret1 = "ret[" ~ J.to!string ~ "].type = "; - static if(is(param[I] == int)) + enum OutArgsInit = ""; + } + else + { + static if(tuple & ParameterStorageClass.out_) { - enum ret2 = "ValueType.Integer;"; + enum add = 1; + enum ret1 = "ret[" ~ J.to!string ~ "].type = "; + static if(is(param[I] == int)) + { + enum ret2 = "ValueType.Integer;"; + } + enum result = ret1 ~ ret2; + } + else + { + enum add = 0; + enum result = ""; + } + static if(param.length > I + 1) + { + enum OutArgsInit = result ~ OutArgsInit!(T, N, I + 1, J + add); + } + else + { + enum OutArgsInit = result; } - enum result = ret1 ~ ret2; - } - else - { - enum add = 0; - enum result = ""; - } - static if(param.length > I + 1) - { - enum OutArgsInit = result ~ OutArgsInit!(T, N, I + 1, J + add); - } - else - { - enum OutArgsInit = result; } } template GetArgumentCount(T, string N, int I = 0) @@ -522,3 +665,20 @@ template GetArgumentCount(T, string N, int I = 0) enum GetArgumentCount = add; } } +template IsVariadic(T, string N, int I = 0) +{ + alias param = ParameterTypeTuple!(__traits(getMember, T, N)); + static if(param.length == 0 || param.length <= I) + { + enum IsVariadic = false; + } + else static if(is(param[I] == Value[])) + { + enum IsVariadic = true; + } + else + { + enum IsVariadic = IsVariadic!(T, N, I + 1); + } +} + diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 13f2331..50b0d58 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -33,6 +33,7 @@ class DataTable { Value[] data; int[wstring] label; + //dataIndexは関数ごとに別じゃないといけない int dataIndex; void addData(Value data) { @@ -714,6 +715,7 @@ class Compiler { globalLabel[label.label] = code.length; } + s.data.addLabel(label.label); } break; case NodeType.Goto: @@ -791,6 +793,7 @@ class Compiler case NodeType.CallFunctionStatement: { auto func = cast(CallFunctionStatement)i; + writeln(func.name); auto bfun = otya.smilebasic.builtinfunctions.BuiltinFunction.builtinFunctions.get(func.name, null); if(bfun) { @@ -835,6 +838,9 @@ class Compiler case NodeType.Read: compileRead(cast(Read)i, s); break; + case NodeType.Restore: + genCode(new RestoreCodeS((cast(Constant)(cast(Restore)i).label).value.stringValue)); + break; case NodeType.On: compileOn(cast(On)i, s); break; @@ -907,6 +913,11 @@ class Compiler code[i] = new OnGoto(addresses); } } + if(c.type == CodeType.RestoreCodeS) + { + auto restore = cast(RestoreCodeS)c; + code[i] = new RestoreCode(s.data.label[restore.label], s.data); + } } return new VM(code, globalIndex + 1, global, functions, s.data); } diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index 72b9a54..b57b82e 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -964,12 +964,27 @@ class Parser auto token = lex.front(); while(true) { + bool minusflag; + //TODO:constexpression()関数作る + if(token.type == TokenType.Minus) + { + lex.popFront(); + token = lex.front(); + minusflag = true; + } if(token.type != TokenType.String && token.type != TokenType.Integer) { syntaxError(); return null; } - data.addData(token.value); + if(minusflag) + { + data.addData(Value(-token.value.castDouble)); + } + else + { + data.addData(token.value); + } lex.popFront(); token = lex.front(); if(token.type == TokenType.Comma) diff --git a/SMILEBASIC/petitcomputer.d b/SMILEBASIC/petitcomputer.d index a061d89..f3125d9 100644 --- a/SMILEBASIC/petitcomputer.d +++ b/SMILEBASIC/petitcomputer.d @@ -13,6 +13,7 @@ import otya.smilebasic.parser; import otya.smilebasic.sprite; enum Button { + NONE = 0, UP = 1, DOWN = 2, LEFT = 4, @@ -129,7 +130,7 @@ class PetitComputer } struct ConsoleCharacter { - wchar charater; + wchar character; int foreColor; int backColor; byte attr; @@ -554,7 +555,6 @@ class PetitComputer glAlphaFunc(GL_GEQUAL, 0.5); glEnable(GL_ALPHA_TEST); draw = new otya.smilebasic.draw.Draw(this); - sprite = new Sprite(this); sprite.spset(0, 0); sprite.spofs(0, 9, 8); while(true) @@ -658,12 +658,13 @@ class PetitComputer consolem = new Mutex(); keybuffermutex = new Mutex(); grpmutex = new Mutex(); + sprite = new Sprite(this); core.thread.Thread thread = new core.thread.Thread(&render); thread.start(); auto startTicks = SDL_GetTicks(); //とりあえず auto parser = new Parser( - readText("./SYS/EX7ALIEN.TXT").to!wstring + readText("./SYS/GAME1DOTRC.TXT").to!wstring //readText(input("LOAD PROGRAM:", true).to!string).to!wstring //readText("./SYS/EX1TEXT.TXT").to!wstring //readText("FIZZBUZZ.TXT").to!wstring @@ -730,6 +731,7 @@ class PetitComputer try { printConsole(sbe.to!string); + writeln(sbe.to!string); } catch { @@ -741,6 +743,7 @@ class PetitComputer try { printConsole(t.to!string); + writeln(t); } catch { @@ -993,7 +996,7 @@ class PetitComputer for(int x = 0; x < consoleWidth; x++) { auto fore = consoleColorGL[console[y][x].foreColor]; - auto rect = &fontTable[console[y][x].charater]; + auto rect = &fontTable[console[y][x].character]; glColor4ubv(cast(ubyte*)&fore); glTexCoord2f((rect.x) / 512f - 1 , (rect.y + 8) / 512f - 1); glVertex3f((x * 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0); @@ -1027,7 +1030,7 @@ class PetitComputer } if(c != '\r' && c != '\n') { - console[CSRY][CSRX].charater = c; + console[CSRY][CSRX].character = c; console[CSRY][CSRX].foreColor = consoleForeColor; console[CSRY][CSRX].backColor = consoleBackColor; } diff --git a/SMILEBASIC/sprite.d b/SMILEBASIC/sprite.d index b02ef32..8f90d71 100644 --- a/SMILEBASIC/sprite.d +++ b/SMILEBASIC/sprite.d @@ -49,7 +49,7 @@ class Sprite PetitComputer petitcom; void initUVTable() { - UVTable[0] = SDL_Rect(0, 0, 16, 16);//Ichigo + UVTable[] = SDL_Rect(0, 0, 16, 16);//Ichigo } this(PetitComputer petitcom) { @@ -89,6 +89,10 @@ class Sprite } void spset(int id, int defno) { + if(defno >= 2048 && defno < 4096) + { + defno -= 2048; + } sprites[id] = SpriteData(id, UVTable[defno].x, UVTable[defno].y, UVTable[defno].w, UVTable[defno].h); } void spofs(int id, int x, int y) @@ -96,4 +100,12 @@ class Sprite sprites[id].x = x; sprites[id].y = y; } + void sphide(int id) + { + sprites[id].attr ^= SpriteAttr.show; + } + void spshow(int id) + { + sprites[id].attr |= SpriteAttr.show; + } } diff --git a/SMILEBASIC/type.d b/SMILEBASIC/type.d index 466865a..25c1e1c 100644 --- a/SMILEBASIC/type.d +++ b/SMILEBASIC/type.d @@ -124,6 +124,10 @@ class Array(T) dim[2] = 0; dim[3] = 0; array = new T[len]; + static if(is(T == double)) + { + array[] = 0; + } dimCount = 1; } this(int[] dim) @@ -135,6 +139,10 @@ class Array(T) this.dim[i] = dim[i]; } array = new T[len]; + static if(is(T == double)) + { + array[] = 0; + } dimCount = dim.length; } T opIndexAssign(T v, int[] dim)