GBOXを実装,GCLSを実装,システム変数DATE$TIME$を実装,そのほか関数を実装,TRUE/FALSEを追加,小数点リテラルを実装.
This commit is contained in:
@@ -207,11 +207,13 @@
|
||||
<Folder name="SMILEBASIC">
|
||||
<File path="builtinfunctions.d" />
|
||||
<File path="compiler.d" />
|
||||
<File path="draw.d" />
|
||||
<File path="error.d" />
|
||||
<File path="main.d" />
|
||||
<File path="node.d" />
|
||||
<File path="parser.d" />
|
||||
<File path="petitcomputer.d" />
|
||||
<File path="systemvariable.d" />
|
||||
<File path="TEST.txt" />
|
||||
<File path="token.d" />
|
||||
<File path="type.d" />
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
GOSUB@A
|
||||
GOTO@B
|
||||
'A=SIN(B)
|
||||
'?Y2,SIN(DAY * 2 * 3.141 / BDAY),LINEH,LINEC
|
||||
@A
|
||||
Y2 = LINEC - SIN(DAY * 2 * 3 / BDAY) * LINEH
|
||||
RETURN
|
||||
@B
|
||||
?DATE$, TIME$
|
||||
DTREAD "2014/10/12" OUT Y,M,D
|
||||
?Y,M,D
|
||||
?SIN(1)
|
||||
'COMMENT'
|
||||
ASSERT__ 1, "TRUE"
|
||||
A$="A"
|
||||
@@ -80,14 +92,18 @@ DEF ONGOSUBTEST
|
||||
@4
|
||||
END
|
||||
@DATA_1
|
||||
DATA "A",1,2,3,4
|
||||
DIM ARY[2]
|
||||
DATA "A",1,2,3,4,5
|
||||
READ DATA$,_1,_2
|
||||
READ _3,_4
|
||||
READ ARY[_1]
|
||||
ASSERT__ DATA$=="A", "DATA"
|
||||
ASSERT__ _1==1, "DATA"
|
||||
ASSERT__ _2==2, "DATA"
|
||||
ASSERT__ _3==3, "DATA"
|
||||
ASSERT__ _4==4, "DATA"
|
||||
ASSERT__ ARY[1]==5, "DATA"
|
||||
?ARY[_1]
|
||||
INPUT$="HELLO"
|
||||
INPUT INPUT$,IN
|
||||
?INPUT$,IN
|
||||
|
||||
@@ -4,6 +4,7 @@ import otya.smilebasic.token;
|
||||
import otya.smilebasic.error;
|
||||
import otya.smilebasic.compiler;
|
||||
import otya.smilebasic.petitcomputer;
|
||||
import otya.smilebasic.systemvariable;
|
||||
import std.uni;
|
||||
import std.utf;
|
||||
import std.conv;
|
||||
@@ -17,6 +18,10 @@ struct VMVariable
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
}
|
||||
this(int index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
class VM
|
||||
{
|
||||
@@ -38,7 +43,8 @@ class VM
|
||||
this.globalTable = globalTable;
|
||||
foreach(wstring k, VMVariable v ; globalTable)
|
||||
{
|
||||
this.global[v.index] = Value(v.type);
|
||||
if(v.index >= 0)
|
||||
this.global[v.index] = Value(v.type);
|
||||
}
|
||||
this.functions = functions;
|
||||
this.globalDataTable = gdt;
|
||||
@@ -889,10 +895,16 @@ class CallBuiltinFunction : Code
|
||||
else
|
||||
{
|
||||
arg = vm.stack[vm.stacki - argcount..vm.stacki];
|
||||
result = vm.stack[vm.stacki - argcount..vm.stacki - argcount + outcount];//雑;
|
||||
result = vm.stack[vm.stacki/* - argcount */+ 1..vm.stacki + 1/* - argcount */+ outcount];//雑;
|
||||
}
|
||||
func.func(vm.petitcomputer, arg, result);
|
||||
vm.stacki -= func.argments.length - outcount;
|
||||
vm.stacki -= func.argments.length;// - outcount;
|
||||
////vm.stacki += outcount;
|
||||
//vm.stacki = old;
|
||||
for(int i = 0; i < result.length; i++)
|
||||
{
|
||||
vm.push(result[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
class IncCodeG : Code
|
||||
@@ -1139,3 +1151,29 @@ class ReadCode : Code
|
||||
}
|
||||
}
|
||||
}
|
||||
class PushSystemVariable : Code
|
||||
{
|
||||
SystemVariable var;
|
||||
this(SystemVariable var)
|
||||
{
|
||||
this.var = var;
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.push(var.value);
|
||||
}
|
||||
}
|
||||
class PopSystemVariable : Code
|
||||
{
|
||||
SystemVariable var;
|
||||
this(SystemVariable var)
|
||||
{
|
||||
this.var = var;
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
Value v;
|
||||
vm.pop(v);
|
||||
var.value = v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ struct DefaultValue(T, bool skippable = true)
|
||||
{
|
||||
T value;
|
||||
bool isDefault;
|
||||
this(int v, bool f)
|
||||
this(T v, bool f)
|
||||
{
|
||||
value = v;
|
||||
isDefault = f;
|
||||
}
|
||||
this(int v)
|
||||
this(T v)
|
||||
{
|
||||
value = v;
|
||||
isDefault = false;
|
||||
@@ -67,6 +67,10 @@ class BuiltinFunction
|
||||
return a < 0 ? -a : a;
|
||||
}*/
|
||||
static double function(double) ABS = &abs!double;
|
||||
static double SIN(double arg1)
|
||||
{
|
||||
return sin(arg1);
|
||||
}
|
||||
//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, false) z)
|
||||
{
|
||||
@@ -115,16 +119,84 @@ class BuiltinFunction
|
||||
static void DISPLAY(PetitComputer p, DefaultValue!(int, false) display)
|
||||
{
|
||||
}
|
||||
static void GCLS(PetitComputer p, DefaultValue!(int, false) display)
|
||||
static void GCLS(PetitComputer p, DefaultValue!(int, false) color)
|
||||
{
|
||||
color.setDefaultValue(p.gcolor);
|
||||
p.gfill(p.useGRP, 0, 0, 511, 511, cast(int)color);
|
||||
}
|
||||
static void GPSET(PetitComputer p, int x, int y, DefaultValue!(int, false) color)
|
||||
{
|
||||
//p.gpset(p.useGRP, x, y, );
|
||||
color.setDefaultValue(p.gcolor);
|
||||
p.gpset(p.useGRP, x, y, cast(int)color);
|
||||
}
|
||||
static void GLINE(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
|
||||
{
|
||||
color.setDefaultValue(p.gcolor);
|
||||
p.gline(p.useGRP, x, y, x2, y2, cast(int)color);
|
||||
}
|
||||
static void GBOX(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
|
||||
{
|
||||
color.setDefaultValue(p.gcolor);
|
||||
p.gbox(p.useGRP, x, y, x2, y2, cast(int)color);
|
||||
}
|
||||
static void GFILL(PetitComputer p, int x, int y, int x2, int y2, DefaultValue!(int, false) color)
|
||||
{
|
||||
color.setDefaultValue(p.gcolor);
|
||||
p.gfill(p.useGRP, x, y, x2, y2, cast(int)color);
|
||||
}
|
||||
static void GCOLOR(PetitComputer p, int color)
|
||||
{
|
||||
p.gcolor = color;
|
||||
}
|
||||
static void BEEP(PetitComputer p, DefaultValue!(int, false) display)
|
||||
{
|
||||
}
|
||||
static int RGB(int R, int G, int B, DefaultValue!(int, false) _)
|
||||
{
|
||||
if(!_.isDefault)
|
||||
{
|
||||
//やや強引なオーバーロード
|
||||
return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B, cast(ubyte)_);
|
||||
}
|
||||
return PetitComputer.RGB(cast(ubyte)R, cast(ubyte)G, cast(ubyte)B);
|
||||
}
|
||||
static int RND(int max)
|
||||
{
|
||||
import std.random;
|
||||
return uniform(0, max - 1);
|
||||
}
|
||||
static void DTREAD(DefaultValue!(wstring, false) date, out int Y, out int M, out int D/*W*/)
|
||||
{
|
||||
import std.datetime;
|
||||
auto currentTime = Clock.currTime();
|
||||
if(date.isDefault)
|
||||
{
|
||||
Y = currentTime.year;
|
||||
M = currentTime.month;
|
||||
D = currentTime.day;
|
||||
}
|
||||
else
|
||||
{
|
||||
import std.format;
|
||||
auto v = date.value;
|
||||
formattedRead(v, "%d/%d/%d", &Y, &M, &D);
|
||||
}
|
||||
}
|
||||
//hairetuha?
|
||||
static int LEN(wstring str)
|
||||
{
|
||||
return str.length;
|
||||
}
|
||||
static double VAL(wstring str)
|
||||
{
|
||||
double val = str.to!double;
|
||||
return val;
|
||||
}
|
||||
static wstring MID(wstring str, int i, int len)
|
||||
{
|
||||
//挙動未定
|
||||
return str[i..i + len];
|
||||
}
|
||||
//alias void function(PetitComputer, Value[], Value[]) BuiltinFunc;
|
||||
static BuiltinFunction[wstring] builtinFunctions;
|
||||
static this()
|
||||
@@ -134,7 +206,13 @@ class BuiltinFunction
|
||||
writeln(name);
|
||||
static if(/*__traits(isStaticFunction, __traits(getMember, BuiltinFunction, name)) && */name[0].isUpper)
|
||||
{
|
||||
builtinFunctions[name] = new BuiltinFunction(
|
||||
pragma(msg, AddFunc!(BuiltinFunction, name));
|
||||
wstring suffix = "";
|
||||
if(is(ReturnType!(__traits(getMember, BuiltinFunction, name)) == wstring))
|
||||
{
|
||||
suffix = "$";
|
||||
}
|
||||
builtinFunctions[name ~ suffix] = new BuiltinFunction(
|
||||
GetFunctionParamType!(BuiltinFunction, name),
|
||||
GetFunctionReturnType!(BuiltinFunction, name),
|
||||
mixin(AddFunc!(BuiltinFunction, name)),
|
||||
@@ -179,6 +257,10 @@ template GetFunctionReturnType(T, string N)
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.Void;
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.String;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum GetFunctionReturnType = ValueType.Void;
|
||||
@@ -190,12 +272,22 @@ template AddFunc(T, string N)
|
||||
static if(is(ReturnType!(__traits(getMember, T, N)) == double) || is(ReturnType!(__traits(getMember, T, N)) == int))
|
||||
{
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}ret[0] = Value(" ~ N ~ "(" ~
|
||||
AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}";
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N
|
||||
, 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 != 0){throw new IllegalFunctionCall();}" ~ N ~ "(" ~
|
||||
AddFuncArg!(ParameterTypeTuple!(__traits(getMember, T, N)).length - 1, 0, 0, ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}";
|
||||
|
||||
pragma(msg, GetArgumentCount!(T,N));
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){/*if(ret.length != 0){throw new IllegalFunctionCall();}*/" ~ OutArgsInit!(T,N) ~ N ~ "(" ~
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N,
|
||||
ParameterTypeTuple!(__traits(getMember, T, N))) ~ ");}";
|
||||
}
|
||||
else static if(is(ReturnType!(__traits(getMember, T, N)) == wstring))
|
||||
{
|
||||
const string AddFunc = "function void(PetitComputer p, Value[] arg, Value[] ret){if(ret.length != 1){throw new IllegalFunctionCall();}ret[0] = Value(" ~ N ~ "(" ~
|
||||
AddFuncArg!(/*ParameterTypeTuple!(__traits(getMember, T, N)).length*/GetArgumentCount!(T,N) - 1, 0, 0, 0, T, N
|
||||
, ParameterTypeTuple!(__traits(getMember, T, N))) ~ "));}";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -217,6 +309,20 @@ DefaultValue!(int, false) fromIntToSkip(Value v)
|
||||
else
|
||||
return DefaultValue!(int, false)(true);
|
||||
}
|
||||
DefaultValue!wstring fromStringToDefault(Value v)
|
||||
{
|
||||
if(v.type == ValueType.String)
|
||||
return DefaultValue!wstring(v.castString());
|
||||
else
|
||||
return DefaultValue!wstring(true);
|
||||
}
|
||||
DefaultValue!(wstring, false) fromStringToSkip(Value v)
|
||||
{
|
||||
if(v.type == ValueType.String)
|
||||
return DefaultValue!(wstring, false)(v.castString());
|
||||
else
|
||||
return DefaultValue!(wstring, false)(true);
|
||||
}
|
||||
template GetFunctionParamType(T, string N)
|
||||
{
|
||||
enum GetFunctionParamType = mixin("[" ~ Array!(ParameterTypeTuple!(__traits(getMember, T, N))) ~ "]");
|
||||
@@ -249,6 +355,14 @@ template GetFunctionParamType(T, string N)
|
||||
{
|
||||
const string arg = "ValueType.Integer, true";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(wstring)))
|
||||
{
|
||||
const string arg = "ValueType.String, false";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(wstring, false)))
|
||||
{
|
||||
const string arg = "ValueType.String, true";
|
||||
}
|
||||
else static if(is(P[0] == PetitComputer))
|
||||
{
|
||||
static if(P.length != 0)
|
||||
@@ -271,42 +385,71 @@ template GetFunctionParamType(T, string N)
|
||||
}
|
||||
}
|
||||
}
|
||||
template AddFuncArg(int L, int N, int M, P...)
|
||||
template AddFuncArg(int L, int N, int M, int O, T, string NAME, P...)
|
||||
{
|
||||
enum I = L - N;
|
||||
enum storage = ParameterStorageClassTuple!(__traits(getMember, T, NAME))[M];
|
||||
static if(is(P[0] == double))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castDouble";
|
||||
}
|
||||
else static if(is(P[0] == PetitComputer))
|
||||
{
|
||||
enum add = 0;
|
||||
enum outadd = 0;
|
||||
const string arg = "p";
|
||||
}
|
||||
else static if(is(P[0] == int))
|
||||
{
|
||||
enum add = 1;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castInteger";
|
||||
static if(storage & ParameterStorageClass.out_)
|
||||
{
|
||||
enum add = 0;
|
||||
enum outadd = 1;
|
||||
const string arg = "ret[" ~ O.to!string ~ "].integerValue";
|
||||
}
|
||||
else
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castInteger";
|
||||
}
|
||||
}
|
||||
else static if(is(P[0] == wstring))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "arg[" ~ I.to!string ~ "].castString";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!int))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromIntToDefault(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(int, false)))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromIntToSkip(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!wstring))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromStringToDefault(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
else static if(is(P[0] == DefaultValue!(wstring, false)))
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
const string arg = "fromStringToSkip(arg[" ~ I.to!string ~ "])";
|
||||
}
|
||||
else
|
||||
{
|
||||
enum add = 1;
|
||||
enum outadd = 0;
|
||||
static assert(false, "Invalid type");
|
||||
const string arg = "";
|
||||
}
|
||||
@@ -316,6 +459,62 @@ template AddFuncArg(int L, int N, int M, P...)
|
||||
}
|
||||
else
|
||||
{
|
||||
const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, P[1..$]);
|
||||
const string AddFuncArg = arg ~ ", " ~ AddFuncArg!(L - !add, N + add, M + 1, O + outadd, T, NAME, P[1..$]);
|
||||
}
|
||||
}
|
||||
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_)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
template GetArgumentCount(T, string N, int I = 0)
|
||||
{
|
||||
enum tuple = ParameterStorageClassTuple!(__traits(getMember, T, N))[I];
|
||||
alias param = ParameterTypeTuple!(__traits(getMember, T, N));
|
||||
static if(is(param[I] == PetitComputer))
|
||||
{
|
||||
enum add = 0 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
static if(tuple & ParameterStorageClass.out_)
|
||||
{
|
||||
enum add = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum add = 1;
|
||||
}
|
||||
}
|
||||
static if(param.length > I + 1)
|
||||
{
|
||||
enum GetArgumentCount = add + GetArgumentCount!(T, N, I + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
enum GetArgumentCount = add;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import otya.smilebasic.token;
|
||||
import otya.smilebasic.vm;
|
||||
import otya.smilebasic.type;
|
||||
import otya.smilebasic.error;
|
||||
import otya.smilebasic.systemvariable;
|
||||
import std.stdio;
|
||||
class Scope
|
||||
{
|
||||
@@ -145,6 +146,7 @@ class Compiler
|
||||
case '%':
|
||||
return ValueType.Integer;
|
||||
default:
|
||||
return ValueType.Double;//非DEFINT時
|
||||
return ValueType.Integer;//DEFINT時
|
||||
}
|
||||
}
|
||||
@@ -153,8 +155,13 @@ class Compiler
|
||||
{
|
||||
this.statements = statements;
|
||||
code = new Code[0];
|
||||
global["DATE$"] = VMVariable(-1);
|
||||
sysVariable["DATE$"] = new Date();
|
||||
global["TIME$"] = VMVariable(-1);
|
||||
sysVariable["TIME$"] = new Time();
|
||||
}
|
||||
|
||||
SystemVariable[wstring] sysVariable;
|
||||
Code[] code;
|
||||
VMVariable[wstring] global;
|
||||
int[wstring] globalLabel;
|
||||
@@ -176,6 +183,19 @@ class Compiler
|
||||
{
|
||||
code ~= new PopG(ind);
|
||||
}
|
||||
SystemVariable getSystemVariable(wstring name)
|
||||
{
|
||||
auto var = sysVariable.get(name, null);
|
||||
return var;
|
||||
}
|
||||
void genCodePushSysVar(wstring name)
|
||||
{
|
||||
code ~= new PushSystemVariable(getSystemVariable(name));
|
||||
}
|
||||
void genCodePopSysVar(wstring name)
|
||||
{
|
||||
code ~= new PopSystemVariable(getSystemVariable(name));
|
||||
}
|
||||
void genCodePushVar(wstring name, Scope sc)
|
||||
{
|
||||
auto global = hasGlobalVarIndex(name);
|
||||
@@ -186,6 +206,11 @@ class Compiler
|
||||
}
|
||||
if(global)
|
||||
{
|
||||
if(global < 0)
|
||||
{
|
||||
genCodePushSysVar(name);
|
||||
return;
|
||||
}
|
||||
code ~= new PushG(global);
|
||||
return;
|
||||
}
|
||||
@@ -201,6 +226,11 @@ class Compiler
|
||||
}
|
||||
if(global)
|
||||
{
|
||||
if(global < 0)
|
||||
{
|
||||
genCodePopSysVar(name);
|
||||
return;
|
||||
}
|
||||
code ~= new PopG(global);
|
||||
return;
|
||||
}
|
||||
@@ -371,13 +401,17 @@ class Compiler
|
||||
case NodeType.CallFunction:
|
||||
{
|
||||
auto func = cast(CallFunction)exp;
|
||||
writeln(func.name);
|
||||
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)
|
||||
if(bfun.argments.length >= func.args.length)
|
||||
{
|
||||
genCodeImm(Value(ValueType.Void));
|
||||
auto k = bfun.argments.length - func.args.length;
|
||||
foreach(l;0..k)
|
||||
{
|
||||
genCodeImm(Value(ValueType.Void));
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach_reverse(Expression i ; func.args)
|
||||
@@ -418,10 +452,11 @@ class Compiler
|
||||
case NodeType.Variable:
|
||||
{
|
||||
auto var = cast(Variable)expr;
|
||||
int index;
|
||||
bool local;
|
||||
getVarIndex(var.name, sc, index, local);
|
||||
genCode(local ? new PopL(index) : new PopG(index));
|
||||
genCodePopVar(var.name, sc);
|
||||
//int index;
|
||||
//bool local;
|
||||
//getVarIndex(var.name, sc, index, local);
|
||||
//genCode(local ? new PopL(index) : new PopG(index));
|
||||
}
|
||||
break;
|
||||
case NodeType.BinaryOperator:
|
||||
|
||||
@@ -5,6 +5,7 @@ import otya.smilebasic.node;
|
||||
import otya.smilebasic.compiler;
|
||||
import std.ascii;
|
||||
import std.stdio;
|
||||
import std.conv;
|
||||
class Lexical
|
||||
{
|
||||
TokenType[] table;
|
||||
@@ -60,6 +61,7 @@ class Lexical
|
||||
reserved["DIM"] = TokenType.Var;
|
||||
reserved["DEF"] = TokenType.Def;
|
||||
reserved["OUT"] = TokenType.Out;
|
||||
reserved["out"] = TokenType.Out;//ekkitou
|
||||
reserved["WHILE"] = TokenType.While;
|
||||
reserved["WEND"] = TokenType.WEnd;
|
||||
reserved["INC"] = TokenType.Inc;
|
||||
@@ -69,6 +71,8 @@ class Lexical
|
||||
reserved["RESTORE"] = TokenType.Restore;
|
||||
reserved["ON"] = TokenType.On;
|
||||
reserved["INPUT"] = TokenType.Input;
|
||||
reserved["TRUE"] = TokenType.True;
|
||||
reserved["FALSE"] = TokenType.False;
|
||||
reserved.rehash();
|
||||
line = 1;
|
||||
}
|
||||
@@ -103,19 +107,34 @@ class Lexical
|
||||
token = Token(TokenType.NewLine);
|
||||
break;
|
||||
}
|
||||
if(c.isDigit())
|
||||
if(c.isDigit() || c == '.')
|
||||
{
|
||||
int num;
|
||||
bool dot;
|
||||
int start = i;
|
||||
double num;
|
||||
for(;i < code.length;i++)
|
||||
{
|
||||
c = code[i];
|
||||
if(!c.isDigit())
|
||||
if(c == '.')
|
||||
{
|
||||
if(dot) break;
|
||||
dot = true;
|
||||
}
|
||||
if(!c.isDigit() && c != '.')
|
||||
{
|
||||
break;
|
||||
}
|
||||
num = num * 10 + (c - '0');
|
||||
}
|
||||
token = Token(TokenType.Integer, Value(num));
|
||||
wstring numstr = code[start..i];
|
||||
num = numstr.to!double;
|
||||
if(num <= int.max && num >= int.min && !dot)
|
||||
{
|
||||
token = Token(TokenType.Integer, Value(cast(int)num));
|
||||
}
|
||||
else
|
||||
{
|
||||
token = Token(TokenType.Integer, Value(num));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(c.isAlpha() || c == '_')
|
||||
@@ -138,6 +157,17 @@ class Lexical
|
||||
else//変数が予約語であることはありえない
|
||||
{
|
||||
auto r = reserved.get(iden, TokenType.Unknown);
|
||||
//TRUE/FALSEは3.1でもDATAに使える定数
|
||||
if(r == TokenType.True)
|
||||
{
|
||||
token = Token(TokenType.Integer, Value(1));
|
||||
break;
|
||||
}
|
||||
if(r == TokenType.False)
|
||||
{
|
||||
token = Token(TokenType.Integer, Value(0));
|
||||
break;
|
||||
}
|
||||
if(r != TokenType.Unknown)
|
||||
{
|
||||
token = Token(r);
|
||||
@@ -628,6 +658,20 @@ class Parser
|
||||
}
|
||||
}
|
||||
lex.popFront();
|
||||
auto token = lex.front;
|
||||
if(token.type == TokenType.Iden)
|
||||
{
|
||||
//NEXT I[,J[,K...]]プチコン3号だと無視
|
||||
lex.popFront();
|
||||
token = lex.front;
|
||||
while(token.type == TokenType.Comma)
|
||||
{
|
||||
lex.popFront();
|
||||
token = lex.front;
|
||||
if(token.type != TokenType.Iden) break;
|
||||
lex.popFront();
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
Statements whileStatements()
|
||||
@@ -655,6 +699,7 @@ class Parser
|
||||
{
|
||||
auto token = lex.front();
|
||||
Statement node = null;
|
||||
writeln(token.type);
|
||||
switch(token.type)
|
||||
{
|
||||
case TokenType.Print:
|
||||
@@ -694,6 +739,7 @@ class Parser
|
||||
if(expr)
|
||||
func.addArg(expr);
|
||||
}
|
||||
if(lex.front().type == TokenType.Out) break;
|
||||
if(lex.front().type != TokenType.Comma) break;
|
||||
lex.popFront();
|
||||
}
|
||||
@@ -753,8 +799,7 @@ class Parser
|
||||
node = if_();
|
||||
return node;
|
||||
case TokenType.For:
|
||||
node = forStatement();
|
||||
break;
|
||||
return forStatement();
|
||||
case TokenType.Return:
|
||||
lex.popFront();
|
||||
if(isFuncReturnExpr)
|
||||
|
||||
@@ -123,6 +123,8 @@ class PetitComputer
|
||||
ConsoleCharacter[][] console;
|
||||
bool visibleGRP = true;
|
||||
int showGRP;
|
||||
int useGRP;
|
||||
uint gcolor;
|
||||
GraphicPage[] GRP;
|
||||
GraphicPage GRPF;
|
||||
GraphicPage[] GRPFColor;
|
||||
@@ -261,6 +263,19 @@ class PetitComputer
|
||||
}
|
||||
return new GraphicPage(surface);
|
||||
}
|
||||
GraphicPage createEmptyPage()
|
||||
{
|
||||
auto surface = SDL_CreateRGBSurface(0, 512, 512, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0xff);
|
||||
auto pixels = (cast(uint*)surface.pixels);
|
||||
for(int x = 0; x < surface.w; x++)
|
||||
{
|
||||
for(int y = 0; y < surface.h; y++)
|
||||
{
|
||||
*pixels++ = 0;
|
||||
}
|
||||
}
|
||||
return new GraphicPage(surface);
|
||||
}
|
||||
struct Point
|
||||
{
|
||||
int x, y;
|
||||
@@ -382,7 +397,7 @@ class PetitComputer
|
||||
GRP = new GraphicPage[6];
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
GRP[i] = new GraphicPage(SDL_CreateRGBSurface(0, 512, 512, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0xff));
|
||||
GRP[i] = createEmptyPage();
|
||||
}
|
||||
GRP[4] = createGRPF(spriteFile);
|
||||
GRP[5] = createGRPF(BGFile);
|
||||
@@ -431,9 +446,43 @@ class PetitComputer
|
||||
keybufferlen = keybuffer.length;
|
||||
keybufferpos = (keybufferpos + 1) % keybuffer.length;
|
||||
}
|
||||
Mutex grpmutex;
|
||||
otya.smilebasic.draw.Draw draw;
|
||||
void renderGraphic()
|
||||
{
|
||||
//grpmutex.lock();
|
||||
//scope(exit)
|
||||
// grpmutex.unlock();
|
||||
drawflag = true;
|
||||
//betuni kouzoutai demo sonnnani sokudo kawaranasasou
|
||||
auto len = drawMessageLength;
|
||||
drawMessageLength = 0;
|
||||
for(int i = 0; i < len; i++)
|
||||
{
|
||||
DrawMessage dm = drawMessageQueue[i];
|
||||
switch(dm.type)
|
||||
{
|
||||
case DrawType.PSET:
|
||||
draw.gpset(dm.page, dm.x, dm.y ,dm.color);
|
||||
break;
|
||||
case DrawType.LINE:
|
||||
draw.gline(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color);
|
||||
break;
|
||||
case DrawType.FILL:
|
||||
draw.gfill(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color);
|
||||
break;
|
||||
case DrawType.BOX:
|
||||
draw.gbox(dm.page, dm.x, dm.y ,dm.x2, dm.y2, dm.color);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
drawflag = false;
|
||||
|
||||
}
|
||||
void render()
|
||||
{
|
||||
bool renderprofile = true;
|
||||
bool renderprofile;
|
||||
try
|
||||
{
|
||||
version(Windows)
|
||||
@@ -471,8 +520,12 @@ class PetitComputer
|
||||
g.createTexture(renderer);
|
||||
}
|
||||
//GRP[0] = GRPF;
|
||||
gpset(0, 10, 10, 0xFF00FF00);
|
||||
gline(0, 0, 0, 399, 239, RGB(0, 255, 0));
|
||||
//glEnable(GL_BLEND);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glAlphaFunc(GL_GEQUAL, 0.5);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
draw = new otya.smilebasic.draw.Draw(this);
|
||||
while(true)
|
||||
{
|
||||
auto profile = SDL_GetTicks();
|
||||
@@ -486,9 +539,10 @@ class PetitComputer
|
||||
loopcnt = 0;
|
||||
}
|
||||
}
|
||||
renderGraphic();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
//renderConsoleGL();
|
||||
renderGraphicPage();
|
||||
renderConsoleGL();
|
||||
SDL_GL_SwapWindow(window);
|
||||
auto renderticks = (SDL_GetTicks() - profile);
|
||||
if(renderprofile) writeln(renderticks);
|
||||
@@ -528,9 +582,18 @@ class PetitComputer
|
||||
break;
|
||||
}
|
||||
}
|
||||
long delay = (1000/60) - cast(long)(SDL_GetTicks() - profile);
|
||||
if(delay > 0)
|
||||
SDL_Delay(cast(uint)delay);
|
||||
while(true)
|
||||
{
|
||||
long delay = (1000/60) - cast(long)(SDL_GetTicks() - profile);
|
||||
if(delay > 0)
|
||||
SDL_Delay(cast(uint)delay);
|
||||
break;
|
||||
if(delay < 0) break;
|
||||
renderGraphic();
|
||||
SDL_Delay(1);
|
||||
//if(delay > 0)
|
||||
// SDL_Delay(cast(uint)delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable t)
|
||||
@@ -553,11 +616,13 @@ class PetitComputer
|
||||
|
||||
consolem = new Mutex();
|
||||
keybuffermutex = new Mutex();
|
||||
grpmutex = new Mutex();
|
||||
core.thread.Thread thread = new core.thread.Thread(&render);
|
||||
thread.start();
|
||||
auto startTicks = SDL_GetTicks();
|
||||
//とりあえず
|
||||
auto parser = new Parser(readText(input("LOAD PROGRAM:", true).to!string).to!wstring
|
||||
auto parser = new Parser(readText("./SYS/EX5BIORHYTHM.TXT").to!wstring
|
||||
//readText(input("LOAD PROGRAM:", true).to!string).to!wstring
|
||||
//readText("./SYS/EX1TEXT.TXT").to!wstring
|
||||
//readText("FIZZBUZZ.TXT").to!wstring
|
||||
//readText("TEST.TXT").to!wstring
|
||||
@@ -603,6 +668,10 @@ class PetitComputer
|
||||
auto vm = parser.compile();
|
||||
bool running = true;
|
||||
vm.init(this);
|
||||
gpset(0, 10, 10, 0xFF00FF00);
|
||||
gline(0, 0, 0, 399, 239, RGB(0, 255, 0));
|
||||
gfill(0, 78, 78, 40, 40, RGB(0, 255, 255));
|
||||
gbox(0, 78, 78, 40, 40, RGB(255, 255, 0));
|
||||
while (true)
|
||||
{
|
||||
uint elapse;
|
||||
@@ -712,7 +781,7 @@ class PetitComputer
|
||||
bool animationCursor;
|
||||
Mutex consolem;
|
||||
//プチコン内部表現はRGB5_A1
|
||||
uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a)
|
||||
static uint toGLColor(GLenum format, ubyte r, ubyte g, ubyte b, ubyte a)
|
||||
{
|
||||
if(format == GL_BGRA)
|
||||
{
|
||||
@@ -724,7 +793,7 @@ class PetitComputer
|
||||
}
|
||||
throw new Exception("unsuport enviroment");
|
||||
}
|
||||
uint toGLColor(GLenum format, uint petitcolor)
|
||||
static uint toGLColor(GLenum format, uint petitcolor)
|
||||
{
|
||||
if(format == GL_BGRA)
|
||||
{
|
||||
@@ -737,7 +806,7 @@ class PetitComputer
|
||||
throw new Exception("unsuport enviroment");
|
||||
}
|
||||
//プチコンと違って[A,]R,G,Bじゃない
|
||||
void RGBRead(uint color, out ubyte r, out ubyte g, out ubyte b, out ubyte a)
|
||||
static void RGBRead(uint color, out ubyte r, out ubyte g, out ubyte b, out ubyte a)
|
||||
{
|
||||
//エンディアン関係ない
|
||||
a = color >> 24;
|
||||
@@ -745,62 +814,107 @@ class PetitComputer
|
||||
g = color >> 8 & 0xFF;
|
||||
b = color& 0xFF;
|
||||
}
|
||||
uint RGB(ubyte r, ubyte g, ubyte b)
|
||||
static uint RGB(ubyte r, ubyte g, ubyte b)
|
||||
{
|
||||
return 0xFF000000 | r << 16 | g << 8 | b;
|
||||
}
|
||||
uint RGB(ubyte a, ubyte r, ubyte g, ubyte b)
|
||||
static uint RGB(ubyte a, ubyte r, ubyte g, ubyte b)
|
||||
{
|
||||
return a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
enum DrawType
|
||||
{
|
||||
CLEAR,
|
||||
PSET,
|
||||
LINE,
|
||||
FILL,
|
||||
BOX,
|
||||
CIRCLE,
|
||||
TRI,
|
||||
}
|
||||
struct DrawMessage
|
||||
{
|
||||
DrawType type;
|
||||
byte page;
|
||||
short x;
|
||||
short y;
|
||||
short x2;
|
||||
short y2;
|
||||
uint color;
|
||||
//
|
||||
}
|
||||
static const int dmqqueuelen = 8192;
|
||||
DrawMessage[] drawMessageQueue = new DrawMessage[dmqqueuelen];
|
||||
int drawMessageLength;
|
||||
bool drawflag;
|
||||
void sendDrawMessage(DrawType type, byte page, short x, short y, uint color)
|
||||
{
|
||||
//grpmutex.lock();
|
||||
//scope(exit)
|
||||
// grpmutex.unlock();
|
||||
if(drawMessageLength >= dmqqueuelen)
|
||||
{
|
||||
while(drawMessageLength)
|
||||
{
|
||||
SDL_Delay(1);
|
||||
}
|
||||
}
|
||||
while(drawflag){}
|
||||
drawMessageQueue[drawMessageLength].type = type;
|
||||
drawMessageQueue[drawMessageLength].page = page;
|
||||
drawMessageQueue[drawMessageLength].x = x;
|
||||
drawMessageQueue[drawMessageLength].y = y;
|
||||
drawMessageQueue[drawMessageLength].color = color;
|
||||
drawMessageLength++;
|
||||
}
|
||||
void sendDrawMessage(DrawType type, byte page, short x, short y, short x2, short y2, uint color)
|
||||
{
|
||||
grpmutex.lock();
|
||||
scope(exit)
|
||||
grpmutex.unlock();
|
||||
drawMessageQueue[drawMessageLength].type = type;
|
||||
drawMessageQueue[drawMessageLength].page = page;
|
||||
drawMessageQueue[drawMessageLength].x = x;
|
||||
drawMessageQueue[drawMessageLength].y = y;
|
||||
drawMessageQueue[drawMessageLength].x2 = x2;
|
||||
drawMessageQueue[drawMessageLength].y2 = y2;
|
||||
drawMessageQueue[drawMessageLength].color = color;
|
||||
drawMessageLength++;
|
||||
}
|
||||
//TODO:範囲チェック
|
||||
void gpset(int page, int x, int y, uint color)
|
||||
{
|
||||
color = toGLColor(GRP[page].textureFormat, color);
|
||||
glBindTexture(GL_TEXTURE_2D, GRP[page].glTexture);
|
||||
glTexSubImage2D(GL_TEXTURE_2D , 0, x, y, 1, 1, GRP[page].textureFormat, GL_UNSIGNED_BYTE, &color);
|
||||
sendDrawMessage(DrawType.PSET, cast(byte)page, cast(short)x, cast(short)y, color);
|
||||
}
|
||||
void gline(int page, int x, int y, int x2, int y2, uint color)
|
||||
{
|
||||
import std.math;
|
||||
int dx = abs(x2 - x);
|
||||
int dy = abs(y2 - y);
|
||||
int sx, sy;
|
||||
if(x < x2) sx = 1; else sx = -1;
|
||||
if(y < y2) sy = 1; else sy = -1;
|
||||
int err = dx - dy;
|
||||
while(true)
|
||||
{
|
||||
gpset(page, x, y, color);
|
||||
if(x == x2 && y == y2)break;
|
||||
int e2 = 2*err;
|
||||
if(e2 > -dy)
|
||||
{
|
||||
err = err - dy;
|
||||
x = x + sx;
|
||||
}
|
||||
if(e2 < dx)
|
||||
{
|
||||
err = err + dx;
|
||||
y = y + sy ;
|
||||
}
|
||||
}
|
||||
sendDrawMessage(DrawType.LINE, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color);
|
||||
}
|
||||
void gbox(int page, int x, int y, int x2, int y2, uint color)
|
||||
{
|
||||
sendDrawMessage(DrawType.BOX, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color);
|
||||
}
|
||||
void gfill(int page, int x, int y, int x2, int y2, uint color)
|
||||
{
|
||||
sendDrawMessage(DrawType.FILL, cast(byte)page, cast(short)x, cast(short)y, cast(short)x2, cast(short)y2, color);
|
||||
}
|
||||
void renderGraphicPage()
|
||||
{
|
||||
float z = 0.01f;
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glBindTexture(GL_TEXTURE_2D, GRP[showGRP].glTexture);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0 / 512f - 1 , 240 / 512f - 1);
|
||||
glVertex3f(0 / 200f - 1, 1 - 240 / 120f, 0);
|
||||
glVertex3f(0 / 200f - 1, 1 - 240 / 120f, z);
|
||||
glTexCoord2f(0 / 512f - 1, 0 / 512f - 1);
|
||||
glVertex3f(0 / 200f - 1, 1 - 0 / 120f, 0);
|
||||
glVertex3f(0 / 200f - 1, 1 - 0 / 120f, z);
|
||||
glTexCoord2f(400 / 512f - 1, 0 / 512f - 1);
|
||||
glVertex3f(400 / 200f - 1, 1 - 0 / 120f, 0);
|
||||
glVertex3f(400 / 200f - 1, 1 - 0 / 120f, z);
|
||||
glTexCoord2f(400 / 512f - 1, 240 / 512f - 1);
|
||||
glVertex3f(400 / 200f - 1, 1 - 240 / 120f, 0);
|
||||
glVertex3f(400 / 200f - 1, 1 - 240 / 120f, z);
|
||||
glEnd();
|
||||
glFlush();
|
||||
//glFlush();
|
||||
}
|
||||
void renderConsoleGL()
|
||||
{
|
||||
@@ -829,8 +943,6 @@ class PetitComputer
|
||||
}
|
||||
glEnd();
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
//glAlphaFunc(GL_GEQUAL, 0.5);
|
||||
//glEnable(GL_ALPHA_TEST);
|
||||
@@ -851,7 +963,7 @@ class PetitComputer
|
||||
glVertex3f((x * 8 + 8) / 200f - 1, 1 - (y * 8 + 8) / 120f, 0);
|
||||
}
|
||||
glEnd();
|
||||
glFlush();
|
||||
// glFlush();
|
||||
}
|
||||
void printConsole(T...)(T args)
|
||||
{
|
||||
|
||||
@@ -63,6 +63,8 @@ enum TokenType
|
||||
Restore,
|
||||
On,
|
||||
Input,
|
||||
True,
|
||||
False,
|
||||
}
|
||||
|
||||
struct Token
|
||||
|
||||
Reference in New Issue
Block a user