187 lines
3.3 KiB
D
187 lines
3.3 KiB
D
module otya.smilebasic.vm;
|
|
import otya.smilebasic.type;
|
|
import otya.smilebasic.token;
|
|
import std.uni;
|
|
import std.utf;
|
|
import std.conv;
|
|
import std.stdio;
|
|
class VM
|
|
{
|
|
Code[] code;
|
|
int stacki;
|
|
int pc;
|
|
Value[] stack;
|
|
Value[] global;
|
|
int[wstring] debugTable;
|
|
this(Code[] code, int len, int[wstring] debugTable)
|
|
{
|
|
this.code = code;
|
|
this.stack = new Value[1024 * 1024];
|
|
this.global = new Value[len];
|
|
this.debugTable = debugTable;
|
|
}
|
|
void run()
|
|
{
|
|
for(pc = 0; pc < this.code.length; pc++)
|
|
{
|
|
code[pc].execute(this);
|
|
}
|
|
}
|
|
void push(ref Value value)
|
|
{
|
|
stack[stacki++] = value;
|
|
}
|
|
void pop(out Value value)
|
|
{
|
|
value = stack[--stacki];
|
|
}
|
|
Value testGetGlobaVariable(wstring name)
|
|
{
|
|
return global[debugTable[name]];
|
|
}
|
|
}
|
|
enum CodeType
|
|
{
|
|
Push,
|
|
PushG,
|
|
Operate,
|
|
Return,
|
|
Goto,
|
|
Gosub,
|
|
Print,
|
|
PopG,
|
|
}
|
|
abstract class Code
|
|
{
|
|
CodeType type;
|
|
abstract void execute(VM vm);
|
|
}
|
|
class PrintCode : Code
|
|
{
|
|
int count;
|
|
this(int count)
|
|
{
|
|
this.type = CodeType.Print;
|
|
this.count = count;
|
|
}
|
|
override void execute(VM vm)
|
|
{
|
|
for(int i = 0;i < count; i++)
|
|
{
|
|
Value arg;
|
|
vm.pop(arg);
|
|
switch(arg.type)
|
|
{
|
|
case ValueType.Integer:
|
|
write(arg.integerValue);
|
|
break;
|
|
case ValueType.String:
|
|
write(arg.stringValue);
|
|
break;
|
|
default:
|
|
//type missmatch
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* スタックにPush
|
|
*/
|
|
class Push : Code
|
|
{
|
|
Value imm;
|
|
this(Value imm)
|
|
{
|
|
this.type = CodeType.Push;
|
|
this.imm = imm;
|
|
}
|
|
override void execute(VM vm)
|
|
{
|
|
vm.push(imm);
|
|
}
|
|
}
|
|
|
|
class PushG : Code
|
|
{
|
|
int var;
|
|
this(int var)
|
|
{
|
|
this.type = CodeType.PushG;
|
|
this.var = var;
|
|
}
|
|
override void execute(VM vm)
|
|
{
|
|
vm.push(vm.global[var]);
|
|
}
|
|
}
|
|
class PopG : Code
|
|
{
|
|
int var;
|
|
this(int var)
|
|
{
|
|
this.type = CodeType.PopG;
|
|
this.var = var;
|
|
}
|
|
override void execute(VM vm)
|
|
{
|
|
vm.pop(vm.global[var]);
|
|
}
|
|
}
|
|
class Operate : Code
|
|
{
|
|
TokenType operator;
|
|
this(TokenType op)
|
|
{
|
|
this.operator = op;
|
|
}
|
|
|
|
override void execute(VM vm)
|
|
{
|
|
Value l;
|
|
Value r;
|
|
vm.pop(r);
|
|
vm.pop(l);
|
|
double ld = l.integerValue;
|
|
double rd = r.integerValue;
|
|
//とりあえずInteger
|
|
switch(operator)
|
|
{
|
|
case TokenType.Plus:
|
|
ld += rd;
|
|
break;
|
|
case TokenType.Minus:
|
|
ld -= rd;
|
|
break;
|
|
case TokenType.Mul:
|
|
ld *= rd;
|
|
break;
|
|
case TokenType.Div:
|
|
ld /= rd;
|
|
break;
|
|
default:
|
|
writeln("NotImpl: ", operator);
|
|
break;
|
|
}
|
|
l.integerValue = cast(int)ld;
|
|
vm.push(l);
|
|
}
|
|
}
|
|
class Goto : Code
|
|
{
|
|
int address;
|
|
this(int addr)
|
|
{
|
|
this.type = CodeType.Goto;
|
|
address = addr;
|
|
}
|
|
override void execute(VM vm)
|
|
{
|
|
vm.pc = address - 1;
|
|
}
|
|
}
|
|
class Gosub : Code
|
|
{
|
|
|
|
}
|