1
0
This commit is contained in:
otya128
2015-09-05 16:24:09 +09:00
parent b646b9efca
commit 42e514a989
5 changed files with 151 additions and 61 deletions

View File

@@ -23,48 +23,69 @@ struct VMVariable
this.index = index; this.index = index;
} }
} }
class VM class VMSlot
{ {
bool isUsed;
DataTable globalDataTable; DataTable globalDataTable;
Code[] code; Code[] code;
SourceLocation[] location; SourceLocation[] location;
int stacki;
int pc;
Value[] stack;
Value[] global; Value[] global;
VMVariable[wstring] globalTable; VMVariable[wstring] globalTable;
Function[wstring] functions; Function[wstring] functions;
int[wstring] globalLabel; int[wstring] globalLabel;
DebugInfo debugInfo;
}
class VM
{
static const directModeSlot = 5;
VMSlot[6] slots;
int slot;
VMSlot currentSlot;
int stacki;
int pc;
Value[] stack;
int bp; int bp;
PetitComputer petitcomputer; PetitComputer petitcomputer;
DebugInfo debugInfo; this()
this(Code[] code, int len, VMVariable[wstring] globalTable, Function[wstring] functions, DataTable gdt/*GNU Debugging Tools*/, {
this.stack = new Value[16384];
for(int i = 0; i < slots.length; i++)
{
slots[i] = new VMSlot();
}
}
void setCurrentSlot(int slot)
{
currentSlot = slots[slot];
}
void loadSlot(int slot, Code[] code, int len, VMVariable[wstring] globalTable, Function[wstring] functions, DataTable gdt/*GNU Debugging Tools*/,
int[wstring] globalLabel, DebugInfo dinfo) int[wstring] globalLabel, DebugInfo dinfo)
{ {
this.code = code; auto s = this.slots[slot];
this.stack = new Value[16384]; s.isUsed = true;
this.global = new Value[len]; s.code = code;
this.globalTable = globalTable; s.global = new Value[len];
s.globalTable = globalTable;
foreach(wstring k, VMVariable v ; globalTable) foreach(wstring k, VMVariable v ; globalTable)
{ {
if(v.index >= 0) if(v.index >= 0)
this.global[v.index] = Value(v.type); s.global[v.index] = Value(v.type);
} }
this.functions = functions; s.functions = functions;
this.globalDataTable = gdt; s.globalDataTable = gdt;
this.globalLabel = globalLabel; s.globalLabel = globalLabel;
this.debugInfo = dinfo; s.debugInfo = dinfo;
} }
Code getCurrent() Code getCurrent()
{ {
return code[pc]; return currentSlot.code[pc];
} }
void run() void run()
{ {
bp = 0;//globalを実行なのでbaseは0(グローバル変数をスタックに取るようにしない限り)(挙動的にスタックに確保していなさそう) bp = 0;//globalを実行なのでbaseは0(グローバル変数をスタックに取るようにしない限り)(挙動的にスタックに確保していなさそう)
for(pc = 0; pc < this.code.length; pc++) for(pc = 0; pc < this.currentSlot.code.length; pc++)
{ {
code[pc].execute(this); currentSlot.code[pc].execute(this);
} }
if(stacki != 0) if(stacki != 0)
{ {
@@ -73,7 +94,7 @@ class VM
} }
SourceLocation currentLocation() SourceLocation currentLocation()
{ {
return debugInfo.getLocationByAddress(pc); return currentSlot.debugInfo.getLocationByAddress(pc);
} }
void init(PetitComputer petitcomputer) void init(PetitComputer petitcomputer)
{ {
@@ -82,14 +103,38 @@ class VM
} }
bool runStep() bool runStep()
{ {
if(pc < this.code.length) if(pc < this.currentSlot.code.length)
{ {
code[pc].execute(this); currentSlot.code[pc].execute(this);
pc++; pc++;
return true; return true;
} }
return false; return false;
} }
void poppc()
{
Value value;
pop(value);
if(value.type == ValueType.InternalAddress)
{
pc = value.integerValue;
return;
}
if(value.type == ValueType.InternalSlotAddress)
{
pc = value.internalAddress.address;
setCurrentSlot(value.internalAddress.slot);
return;
}
assert(false, "internal error, compiler bug?");
}
void pushpc()
{
Value value;
value.type = ValueType.InternalAddress;
value.integerValue = pc;
push(value);
}
void push(ref Value value) void push(ref Value value)
{ {
if(stacki >= this.stack.length) if(stacki >= this.stack.length)
@@ -127,20 +172,20 @@ class VM
} }
Value testGetGlobalVariable(wstring name) Value testGetGlobalVariable(wstring name)
{ {
return global[globalTable[name].index]; return currentSlot.global[currentSlot.globalTable[name].index];
} }
void end() void end()
{ {
pc = cast(int)code.length; pc = cast(int)currentSlot.code.length;
} }
void dump() void dump()
{ {
foreach(i, c; code) foreach(i, c; currentSlot.code)
writefln("%04X:%s", i, c.toString(this)); writefln("%04X:%s", i, c.toString(this));
} }
wstring getGlobalVarName(int index) wstring getGlobalVarName(int index)
{ {
foreach(k, v; globalTable) foreach(k, v; currentSlot.globalTable)
{ {
if(v.index == index) return k; if(v.index == index) return k;
} }
@@ -149,21 +194,21 @@ class VM
Value readData() Value readData()
{ {
Value value; Value value;
this.globalDataTable.read(value, this); this.currentSlot.globalDataTable.read(value, this);
return value; return value;
} }
void restoreData(wstring label) void restoreData(wstring label)
{ {
this.globalDataTable.dataIndex = this.globalDataTable.label[label]; this.currentSlot.globalDataTable.dataIndex = this.currentSlot.globalDataTable.label[label];
} }
int olddti; int olddti;
void pushDataIndex() void pushDataIndex()
{ {
olddti = this.globalDataTable.dataIndex; olddti = this.currentSlot.globalDataTable.dataIndex;
} }
void popDataIndex() void popDataIndex()
{ {
this.globalDataTable.dataIndex = olddti; this.currentSlot.globalDataTable.dataIndex = olddti;
} }
} }
enum CodeType enum CodeType
@@ -269,7 +314,7 @@ class PushG : Code
} }
override void execute(VM vm) override void execute(VM vm)
{ {
vm.push(vm.global[var]); vm.push(vm.currentSlot.global[var]);
} }
override string toString(VM vm) override string toString(VM vm)
{ {
@@ -287,28 +332,28 @@ class PopG : Code
override void execute(VM vm) override void execute(VM vm)
{ {
Value v; Value v;
Value g = vm.global[var]; Value g = vm.currentSlot.global[var];
vm.pop(v); vm.pop(v);
if(v.type == ValueType.Integer && g.type == ValueType.Double) if(v.type == ValueType.Integer && g.type == ValueType.Double)
{ {
vm.global[var] = Value(cast(double)v.integerValue); vm.currentSlot.global[var] = Value(cast(double)v.integerValue);
return; return;
} }
if(g.type == ValueType.Integer && v.type == ValueType.Double) if(g.type == ValueType.Integer && v.type == ValueType.Double)
{ {
vm.global[var] = Value(cast(int)v.doubleValue); vm.currentSlot.global[var] = Value(cast(int)v.doubleValue);
return; return;
} }
if(g.type == ValueType.Void) if(g.type == ValueType.Void)
{ {
vm.global[var] = v; vm.currentSlot.global[var] = v;
return; return;
} }
if(v.type != g.type) if(v.type != g.type)
{ {
throw new TypeMismatch(); throw new TypeMismatch();
} }
vm.global[var] = v; vm.currentSlot.global[var] = v;
} }
override string toString(VM vm) override string toString(VM vm)
{ {
@@ -654,7 +699,7 @@ class GotoExpr : Code
vm.pop(label); vm.pop(label);
if(!label.isString) if(!label.isString)
{ {
vm.pc = vm.globalLabel[label.castString] - 1; vm.pc = vm.currentSlot.globalLabel[label.castString] - 1;
} }
else else
{ {
@@ -672,7 +717,7 @@ class GosubAddr : Code
} }
override void execute(VM vm) override void execute(VM vm)
{ {
vm.push(Value(vm.pc)); vm.pushpc;//vm.push(Value(vm.pc));
vm.pc = address - 1; vm.pc = address - 1;
} }
override string toString(VM vm) override string toString(VM vm)
@@ -708,8 +753,8 @@ class GosubExpr : Code
vm.pop(label); vm.pop(label);
if(label.isString) if(label.isString)
{ {
vm.push(Value(vm.pc)); vm.pushpc;//vm.push(Value(vm.pc));
vm.pc = vm.globalLabel[label.castString] - 1; vm.pc = vm.currentSlot.globalLabel[label.castString] - 1;
} }
else else
{ {
@@ -730,14 +775,16 @@ class ReturnSubroutine : Code
{ {
throw new ReturnWithoutGosub(); throw new ReturnWithoutGosub();
} }
vm.pop(pc); /*vm.pop(pc);
if(pc.type != ValueType.Integer || pc.integerValue < 0 || pc.integerValue >= vm.code.length) if(pc.type != ValueType.Integer || pc.integerValue < 0 || pc.integerValue >= vm.currentSlot.code.length)
{ {
stderr.writeln("Internal error:Compiler bug?"); stderr.writeln("Internal error:Compiler bug?");
readln(); readln();
return; return;
} }
vm.pc = pc.integerValue; vm.pc = pc.integerValue;
*/
vm.poppc;
} }
override string toString(VM vm) override string toString(VM vm)
{ {
@@ -896,7 +943,7 @@ class PopArray : Code
} }
else else
{ {
array = vm.global[var]; array = vm.currentSlot.global[var];
} }
if(!array.isArray) if(!array.isArray)
{ {
@@ -969,10 +1016,12 @@ class ReturnFunction : Code
{ {
vm.pop(retexpr); vm.pop(retexpr);
} }
vm.stacki = vm.bp + 2; vm.stacki = vm.bp + Function.frameSize;//2;
Value bp, pc; Value bp, pc;
vm.pop(pc); vm.poppc;//(pc);
vm.pop(bp); vm.pop(bp);
Value hae;
vm.pop(hae);
vm.stacki -= func.argCount; vm.stacki -= func.argCount;
if(func.returnExpr) if(func.returnExpr)
{ {
@@ -983,10 +1032,10 @@ class ReturnFunction : Code
//OUTの実装 //OUTの実装
for(int i = 0; i < func.outArgCount; i++) for(int i = 0; i < func.outArgCount; i++)
{ {
vm.push(vm.stack[vm.bp + i + 2]); vm.push(vm.stack[vm.bp + i + /*2*/Function.frameSize]);
} }
} }
vm.pc = pc.integerValue; //vm.pc = pc.integerValue;
vm.bp = bp.integerValue; vm.bp = bp.integerValue;
} }
override string toString(VM vm) override string toString(VM vm)
@@ -1013,7 +1062,7 @@ class CallFunctionCode : Code
} }
override void execute(VM vm) override void execute(VM vm)
{ {
Function func = vm.functions.get(name, null); Function func = vm.currentSlot.functions.get(name, null);
if(!func) if(!func)
{ {
throw new SyntaxError(name); throw new SyntaxError(name);
@@ -1028,8 +1077,9 @@ class CallFunctionCode : Code
} }
//TODO:args //TODO:args
auto bp = vm.stacki; auto bp = vm.stacki;
vm.push(Value());
vm.push(Value(vm.bp)); vm.push(Value(vm.bp));
vm.push(Value(vm.pc)); vm.pushpc;//vm.push(Value(vm.pc));
vm.bp = bp; vm.bp = bp;
vm.pc = func.address - 1; vm.pc = func.address - 1;
vm.stacki += func.variableIndex - 1; vm.stacki += func.variableIndex - 1;
@@ -1104,7 +1154,7 @@ class IncCodeG : Code
override void execute(VM vm) override void execute(VM vm)
{ {
Value v; Value v;
Value g = vm.global[var]; Value g = vm.currentSlot.global[var];
vm.pop(v); vm.pop(v);
if(!g.isNumber() && g.type != ValueType.String) if(!g.isNumber() && g.type != ValueType.String)
{ {
@@ -1119,15 +1169,15 @@ class IncCodeG : Code
double l = g.castDouble; double l = g.castDouble;
double r = v.castDouble; double r = v.castDouble;
if(v.type == ValueType.Double) if(v.type == ValueType.Double)
vm.global[var] = Value(l + r); vm.currentSlot.global[var] = Value(l + r);
else else
vm.global[var] = Value(cast(int)(l + r)); vm.currentSlot.global[var] = Value(cast(int)(l + r));
} }
else else
{ {
wstring l = g.stringValue; wstring l = g.stringValue;
wstring r = v.stringValue; wstring r = v.stringValue;
vm.global[var] = Value(l ~ r); vm.currentSlot.global[var] = Value(l ~ r);
} }
} }
override string toString(VM vm) override string toString(VM vm)
@@ -1244,7 +1294,7 @@ class OnGosub : OnBase
{ {
int index = on(vm); int index = on(vm);
if(index < 0) return; if(index < 0) return;
vm.push(Value(vm.pc)); vm.pushpc;//vm.push(Value(vm.pc));
vm.pc = index - 1; vm.pc = index - 1;
} }
override string toString(VM vm) override string toString(VM vm)
@@ -1352,7 +1402,7 @@ class ReadCode : Code
for(int i = 0; i < count; i++) for(int i = 0; i < count; i++)
{ {
Value data; Value data;
vm.globalDataTable.read(data, vm); vm.currentSlot.globalDataTable.read(data, vm);
vm.push(data); vm.push(data);
} }
} }

View File

@@ -73,6 +73,7 @@ class DataTable
} }
class Function class Function
{ {
static const frameSize = 3;
int address; int address;
wstring name; wstring name;
int argCount; int argCount;
@@ -82,13 +83,20 @@ class Function
int[wstring] label; int[wstring] label;
bool returnExpr; bool returnExpr;
int outArgCount; int outArgCount;
/**
0:bp
1:pc
2:data table(global)
3:data index
4:function pointer
*/
this(int address, wstring name, bool returnExpr, int argCount) this(int address, wstring name, bool returnExpr, int argCount)
{ {
this.address = address; this.address = address;
this.name = name; this.name = name;
this.returnExpr = returnExpr; this.returnExpr = returnExpr;
this.argCount = argCount; this.argCount = argCount;
this.variableIndex = 1;//0,bp,1,pc this.variableIndex = frameSize - 1;//1;//0,bp,1,pc
if(returnExpr) if(returnExpr)
{ {
outArgCount = 1; outArgCount = 1;
@@ -962,9 +970,10 @@ class Compiler
} }
this.debugInfo.addLocation(i.location, code); this.debugInfo.addLocation(i.location, code);
} }
VM compile() Scope globalScope;
Code[] compileProgram()
{ {
Scope s = new Scope(); Scope s = globalScope = new Scope();
foreach(Statement i ; statements.statements) foreach(Statement i ; statements.statements)
{ {
if(i.type == NodeType.DefineFunction) if(i.type == NodeType.DefineFunction)
@@ -1038,7 +1047,15 @@ class Compiler
code[i] = new RestoreCode(s.data.label[restore.label], s.data); code[i] = new RestoreCode(s.data.label[restore.label], s.data);
} }
} }
VM vm = new VM(code, globalIndex + 1, global, functions, s.data, globalLabel, debugInfo); genCode(new EndVM());
return code;
}
VM compile()
{
compileProgram();
VM vm = new VM();
vm.loadSlot(0, code, globalIndex + 1, global, functions, globalScope.data, globalLabel, debugInfo);
vm.setCurrentSlot(0);
registerSystemVariable(vm); registerSystemVariable(vm);
return vm; return vm;
} }

View File

@@ -495,6 +495,11 @@ class Parser
return - - -1; return - - -1;
} }
} }
auto compiler()
{
auto compiler = new Compiler(parseProgram());
return compiler;
}
auto compile() auto compile()
{ {
auto compiler = new Compiler(parseProgram()); auto compiler = new Compiler(parseProgram());

View File

@@ -1052,11 +1052,11 @@ class PetitComputer
parser = new Parser( parser = new Parser(
//readText("./SYS/GAME6TALK.TXT").to!wstring //readText("./SYS/GAME6TALK.TXT").to!wstring
//readText("./SYS/GAME7EXPAD.TXT").to!wstring //readText("./SYS/GAME7EXPAD.TXT").to!wstring
//readText("./SYS/GAME4SHOOTER.TXT").to!wstring readText("./SYS/GAME4SHOOTER.TXT").to!wstring
//readText("./SYS/GAME2RPG.TXT").to!wstring //readText("./SYS/GAME2RPG.TXT").to!wstring
//readText("./SYS/GAME1DOTRC.TXT").to!wstring //readText("./SYS/GAME1DOTRC.TXT").to!wstring
//readText(input("LOAD PROGRAM:", true).to!string).to!wstring //readText(input("LOAD PROGRAM:", true).to!string).to!wstring
readText("./SYS/EX8TECDEMO.TXT").to!wstring //readText("./SYS/EX8TECDEMO.TXT").to!wstring
//readText("./SYS/EX1TEXT.TXT").to!wstring //readText("./SYS/EX1TEXT.TXT").to!wstring
//readText("FIZZBUZZ.TXT").to!wstring //readText("FIZZBUZZ.TXT").to!wstring
//readText("TEST.TXT").to!wstring //readText("TEST.TXT").to!wstring
@@ -1119,7 +1119,17 @@ class PetitComputer
} }
} }
else else
{/*
if(!vm)
{ {
import otya.smilebasic.vm;
vm = new VM();
vm.init(this);
}
auto prg = input("", true);
parser = new Parser(prg);
vm.code.append(parser.compiler.compileProgram());*/
version(none)
do do
{ {
auto file = input("LOAD PROGRAM:", true).to!string; auto file = input("LOAD PROGRAM:", true).to!string;

View File

@@ -10,6 +10,13 @@ enum ValueType : byte
IntegerArray, IntegerArray,
DoubleArray, DoubleArray,
StringArray, StringArray,
InternalAddress,
InternalSlotAddress,
}
struct VMAddress
{
byte slot;
uint address;
} }
struct Value struct Value
{ {
@@ -23,6 +30,7 @@ struct Value
Array!int integerArray; Array!int integerArray;
Array!double doubleArray; Array!double doubleArray;
Array!wstring stringArray; Array!wstring stringArray;
VMAddress internalAddress;
} }
this(int value) this(int value)
{ {