INC/DECを配列に対応させた
This commit is contained in:
191
SMILEBASIC/VM.d
191
SMILEBASIC/VM.d
@@ -346,6 +346,22 @@ class PushG : Code
|
|||||||
return "pushglobal " ~ vm.getGlobalVarName(var).to!string;
|
return "pushglobal " ~ vm.getGlobalVarName(var).to!string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class PushGRef : Code
|
||||||
|
{
|
||||||
|
int var;
|
||||||
|
this(int var)
|
||||||
|
{
|
||||||
|
this.var = var;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
vm.push(Value(&vm.currentSlot.global[var]));
|
||||||
|
}
|
||||||
|
override string toString(VM vm)
|
||||||
|
{
|
||||||
|
return "pushglobalref " ~ vm.getGlobalVarName(var).to!string;
|
||||||
|
}
|
||||||
|
}
|
||||||
class PopG : Code
|
class PopG : Code
|
||||||
{
|
{
|
||||||
int var;
|
int var;
|
||||||
@@ -402,6 +418,22 @@ class PushL : Code
|
|||||||
return "pushlocal " ~ var.to!string;
|
return "pushlocal " ~ var.to!string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class PushLRef : Code
|
||||||
|
{
|
||||||
|
int var;
|
||||||
|
this(int var)
|
||||||
|
{
|
||||||
|
this.var = var;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
vm.push(Value(&vm.stack[vm.bp + var]));
|
||||||
|
}
|
||||||
|
override string toString(VM vm)
|
||||||
|
{
|
||||||
|
return "pushlocalref " ~ var.to!string;
|
||||||
|
}
|
||||||
|
}
|
||||||
class PopL : Code
|
class PopL : Code
|
||||||
{
|
{
|
||||||
int var;
|
int var;
|
||||||
@@ -951,6 +983,70 @@ class PushArray : Code
|
|||||||
return "pusharray " ~ dim.to!string;
|
return "pusharray " ~ dim.to!string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class PushArrayRef : Code
|
||||||
|
{
|
||||||
|
int dim;
|
||||||
|
this(int dim)
|
||||||
|
{
|
||||||
|
this.dim = dim;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
int[4] index;
|
||||||
|
for(int i = 0; i < dim; i++)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
vm.pop(v);
|
||||||
|
if(v.type == ValueType.Integer)
|
||||||
|
{
|
||||||
|
index[i] = v.integerValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(v.type == ValueType.Double)
|
||||||
|
{
|
||||||
|
index[i] = cast(int)v.doubleValue;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
Value array;
|
||||||
|
vm.pop(array);
|
||||||
|
if(!array.isArray)
|
||||||
|
{
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
if(array.type == ValueType.IntegerArray)
|
||||||
|
{
|
||||||
|
vm.push(Value(&array.integerArray[index[0..dim]]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(array.type == ValueType.DoubleArray)
|
||||||
|
{
|
||||||
|
vm.push(Value(&array.doubleArray[index[0..dim]]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(array.type == ValueType.StringArray)
|
||||||
|
{
|
||||||
|
vm.push(Value(&array.stringArray[index[0..dim]]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(array.type == ValueType.String)
|
||||||
|
{
|
||||||
|
if(dim != 1)
|
||||||
|
{
|
||||||
|
//TODO:syntaxError
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
//String?
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
override string toString(VM vm)
|
||||||
|
{
|
||||||
|
return "pusharrayref " ~ dim.to!string;
|
||||||
|
}
|
||||||
|
}
|
||||||
class PopArray : Code
|
class PopArray : Code
|
||||||
{
|
{
|
||||||
int var;
|
int var;
|
||||||
@@ -1639,3 +1735,98 @@ class DecSP : Code
|
|||||||
vm.decSP;
|
vm.decSP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class PopRererence : Code
|
||||||
|
{
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
Value refv, value;
|
||||||
|
vm.pop(refv);
|
||||||
|
vm.pop(value);
|
||||||
|
if (refv.type == ValueType.Reference)
|
||||||
|
{
|
||||||
|
//TODO:型チェック?
|
||||||
|
*refv.reference = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.type == ValueType.IntegerReference)
|
||||||
|
{
|
||||||
|
if (!value.isNumber)
|
||||||
|
{
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
*refv.integerReference = value.castInteger;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.type == ValueType.DoubleReference)
|
||||||
|
{
|
||||||
|
if (!value.isNumber)
|
||||||
|
{
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
*refv.doubleReference = value.castDouble;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.type == ValueType.StringReference)
|
||||||
|
{
|
||||||
|
if (!value.isString)
|
||||||
|
{
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
*refv.stringReference = value.castString;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class IncRef : Code
|
||||||
|
{
|
||||||
|
//TODO:文字列INCの挙動
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
Value refv;
|
||||||
|
vm.pop(refv);
|
||||||
|
Value v;
|
||||||
|
vm.pop(v);
|
||||||
|
if (refv.type == ValueType.Reference)
|
||||||
|
{
|
||||||
|
if (refv.reference.isNumber && v.isNumber)
|
||||||
|
{
|
||||||
|
if (refv.reference.isDouble)
|
||||||
|
{
|
||||||
|
refv.reference.doubleValue += v.castDouble;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.reference.isInteger)
|
||||||
|
{
|
||||||
|
refv.reference.integerValue += v.castInteger;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refv.reference.isString && v.isString)
|
||||||
|
{
|
||||||
|
refv.reference.stringValue~= v.stringValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refv.type == ValueType.IntegerReference && v.isNumber)
|
||||||
|
{
|
||||||
|
*refv.integerReference += v.castInteger;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.type == ValueType.DoubleReference && v.isNumber)
|
||||||
|
{
|
||||||
|
*refv.doubleReference += v.castDouble;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (refv.type == ValueType.StringReference && v.isString)
|
||||||
|
{
|
||||||
|
*refv.stringReference ~= v.castString;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new TypeMismatch();
|
||||||
|
}
|
||||||
|
override string toString(VM vm)
|
||||||
|
{
|
||||||
|
return "incref";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -280,6 +280,34 @@ class Compiler
|
|||||||
}
|
}
|
||||||
code ~= new PushG(getGlobalVarIndex(name));
|
code ~= new PushG(getGlobalVarIndex(name));
|
||||||
}
|
}
|
||||||
|
void genCodePushVarRef(wstring name, Scope sc)
|
||||||
|
{
|
||||||
|
if(sc.func)
|
||||||
|
{
|
||||||
|
auto local = sc.func.hasLocalVarIndex(name);
|
||||||
|
if(local)
|
||||||
|
{
|
||||||
|
code ~= new PushLRef(local);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto global = hasGlobalVarIndex(name);
|
||||||
|
if(global)
|
||||||
|
{
|
||||||
|
if(global < 0)
|
||||||
|
{
|
||||||
|
throw new SyntaxError();
|
||||||
|
}
|
||||||
|
code ~= new PushGRef(global);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(sc.func)
|
||||||
|
{
|
||||||
|
code ~= new PushLRef(sc.func.getLocalVarIndex(name, this));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
code ~= new PushGRef(getGlobalVarIndex(name));
|
||||||
|
}
|
||||||
void genCodePopVar(wstring name, Scope sc)
|
void genCodePopVar(wstring name, Scope sc)
|
||||||
{
|
{
|
||||||
if(sc.func)
|
if(sc.func)
|
||||||
@@ -527,6 +555,56 @@ class Compiler
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void compilePushReference(Expression exp, Scope sc)
|
||||||
|
{
|
||||||
|
if(!exp)
|
||||||
|
{
|
||||||
|
genCodeImm(Value(ValueType.Void));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(exp.type)
|
||||||
|
{
|
||||||
|
case NodeType.BinaryOperator:
|
||||||
|
{
|
||||||
|
auto binop = cast(BinaryOperator)exp;
|
||||||
|
compileExpression(binop.item1, sc);
|
||||||
|
compileExpression(binop.item2, sc);
|
||||||
|
if(binop.operator == TokenType.LBracket)
|
||||||
|
{
|
||||||
|
IndexExpressions ie = cast(IndexExpressions)binop.item2;
|
||||||
|
if(ie)
|
||||||
|
{
|
||||||
|
genCode(new PushArrayRef(cast(int)ie.expressions.length));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genCode(new PushArrayRef(1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NodeType.Variable:
|
||||||
|
auto var = cast(Variable)exp;
|
||||||
|
genCodePushVarRef(var.name, sc);
|
||||||
|
break;
|
||||||
|
case NodeType.IndexExpressions://[expr,expr,expr,expr]用
|
||||||
|
{
|
||||||
|
auto index = cast(IndexExpressions)exp;
|
||||||
|
int count = 0;
|
||||||
|
foreach_reverse(Expression i; index.expressions)
|
||||||
|
{
|
||||||
|
compileExpression(i, sc);
|
||||||
|
count++;
|
||||||
|
if(count >= 4) break;//念のため
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stderr.writeln("Compile:NotImpl ", exp.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
void compilePopVar(Expression expr, Scope sc)
|
void compilePopVar(Expression expr, Scope sc)
|
||||||
{
|
{
|
||||||
switch(expr.type)
|
switch(expr.type)
|
||||||
@@ -684,15 +762,8 @@ class Compiler
|
|||||||
void compileInc(Inc node, Scope sc)
|
void compileInc(Inc node, Scope sc)
|
||||||
{
|
{
|
||||||
compileExpression(node.expression, sc);
|
compileExpression(node.expression, sc);
|
||||||
int index = sc.func ? sc.func.hasLocalVarIndex(node.name) : 0;
|
compilePushReference(node.name, sc);
|
||||||
if(index)
|
genCode(new IncRef());
|
||||||
{
|
|
||||||
genCode(new IncCodeL(index));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
genCode(new IncCodeG(this.getGlobalVarIndex(node.name)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void compileStatements(Statements statements, Scope sc)
|
void compileStatements(Statements statements, Scope sc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -474,9 +474,9 @@ class While : Statement
|
|||||||
}
|
}
|
||||||
class Inc : Statement
|
class Inc : Statement
|
||||||
{
|
{
|
||||||
wstring name;
|
Expression name;
|
||||||
Expression expression;
|
Expression expression;
|
||||||
this(wstring name, Expression expr, SourceLocation loc)
|
this(Expression name, Expression expr, SourceLocation loc)
|
||||||
{
|
{
|
||||||
super.location = loc;
|
super.location = loc;
|
||||||
this.type = NodeType.Inc;
|
this.type = NodeType.Inc;
|
||||||
|
|||||||
@@ -1151,14 +1151,12 @@ class Parser
|
|||||||
bool dec = token.type == TokenType.Dec;
|
bool dec = token.type == TokenType.Dec;
|
||||||
lex.popFront();
|
lex.popFront();
|
||||||
token = lex.front();
|
token = lex.front();
|
||||||
if(token.type != TokenType.Iden)
|
Expression var = expression();
|
||||||
|
if(!isLValue(var))
|
||||||
{
|
{
|
||||||
syntaxError();
|
syntaxError();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
wstring var = token.value.stringValue;
|
|
||||||
//TODO:Array
|
|
||||||
lex.popFront();
|
|
||||||
token = lex.front();
|
token = lex.front();
|
||||||
Expression expr;
|
Expression expr;
|
||||||
if(token.type == TokenType.Comma)
|
if(token.type == TokenType.Comma)
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ enum ValueType : byte
|
|||||||
StringArray,
|
StringArray,
|
||||||
InternalAddress,
|
InternalAddress,
|
||||||
InternalSlotAddress,
|
InternalSlotAddress,
|
||||||
|
Reference,
|
||||||
|
IntegerReference,
|
||||||
|
DoubleReference,
|
||||||
|
StringReference,
|
||||||
}
|
}
|
||||||
struct VMAddress
|
struct VMAddress
|
||||||
{
|
{
|
||||||
@@ -31,6 +35,10 @@ struct Value
|
|||||||
Array!double doubleArray;
|
Array!double doubleArray;
|
||||||
Array!wstring stringArray;
|
Array!wstring stringArray;
|
||||||
VMAddress internalAddress;
|
VMAddress internalAddress;
|
||||||
|
Value* reference;
|
||||||
|
int* integerReference;
|
||||||
|
double* doubleReference;
|
||||||
|
wstring* stringReference;
|
||||||
}
|
}
|
||||||
this(int value)
|
this(int value)
|
||||||
{
|
{
|
||||||
@@ -55,6 +63,26 @@ struct Value
|
|||||||
stringValue = "";
|
stringValue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this(Value* r)
|
||||||
|
{
|
||||||
|
this.type = ValueType.Reference;
|
||||||
|
reference = r;
|
||||||
|
}
|
||||||
|
this(int* r)
|
||||||
|
{
|
||||||
|
this.type = ValueType.IntegerReference;
|
||||||
|
integerReference = r;
|
||||||
|
}
|
||||||
|
this(double* r)
|
||||||
|
{
|
||||||
|
this.type = ValueType.DoubleReference;
|
||||||
|
doubleReference = r;
|
||||||
|
}
|
||||||
|
this(wstring* r)
|
||||||
|
{
|
||||||
|
this.type = ValueType.StringReference;
|
||||||
|
stringReference = r;
|
||||||
|
}
|
||||||
void castOp(ValueType type)
|
void castOp(ValueType type)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
@@ -94,6 +122,14 @@ struct Value
|
|||||||
{
|
{
|
||||||
return this.type == ValueType.Integer || this.type == ValueType.Double;
|
return this.type == ValueType.Integer || this.type == ValueType.Double;
|
||||||
}
|
}
|
||||||
|
bool isInteger()
|
||||||
|
{
|
||||||
|
return this.type == ValueType.Integer;
|
||||||
|
}
|
||||||
|
bool isDouble()
|
||||||
|
{
|
||||||
|
return this.type == ValueType.Double;
|
||||||
|
}
|
||||||
bool isString()
|
bool isString()
|
||||||
{
|
{
|
||||||
return this.type == ValueType.String;
|
return this.type == ValueType.String;
|
||||||
@@ -240,7 +276,7 @@ class Array(T)
|
|||||||
throw new RangeError();
|
throw new RangeError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T opIndex(int[] dim)
|
ref T opIndex(int[] dim)
|
||||||
{
|
{
|
||||||
import core.exception;
|
import core.exception;
|
||||||
switch(dim.length)
|
switch(dim.length)
|
||||||
@@ -257,25 +293,25 @@ class Array(T)
|
|||||||
throw new RangeError();
|
throw new RangeError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
T opIndex(int i1)
|
ref T opIndex(int i1)
|
||||||
{
|
{
|
||||||
if(dimCount != 1) throw new SyntaxError();
|
if(dimCount != 1) throw new SyntaxError();
|
||||||
if(i1 >= dim[0]) throw new SubscriptOutOfRange();
|
if(i1 >= dim[0]) throw new SubscriptOutOfRange();
|
||||||
return array[i1];
|
return array[i1];
|
||||||
}
|
}
|
||||||
T opIndex(int i1, int i2)
|
ref T opIndex(int i1, int i2)
|
||||||
{
|
{
|
||||||
if(dimCount != 2) throw new SyntaxError();
|
if(dimCount != 2) throw new SyntaxError();
|
||||||
if(i1 >= dim[0] && i2 >= dim[1]) throw new SubscriptOutOfRange();
|
if(i1 >= dim[0] && i2 >= dim[1]) throw new SubscriptOutOfRange();
|
||||||
return array[i1 * dim[0] + i2];
|
return array[i1 * dim[0] + i2];
|
||||||
}
|
}
|
||||||
T opIndex(int i1, int i2, int i3)
|
ref T opIndex(int i1, int i2, int i3)
|
||||||
{
|
{
|
||||||
if(dimCount != 3) throw new SyntaxError();
|
if(dimCount != 3) throw new SyntaxError();
|
||||||
if(i1 >= dim[0] && i2 >= dim[1] && i3 >= dim[2]) throw new SubscriptOutOfRange();
|
if(i1 >= dim[0] && i2 >= dim[1] && i3 >= dim[2]) throw new SubscriptOutOfRange();
|
||||||
return array[i1 * dim[0] * dim[1] + i2 * dim[1] + i3];
|
return array[i1 * dim[0] * dim[1] + i2 * dim[1] + i3];
|
||||||
}
|
}
|
||||||
T opIndex(int i1, int i2, int i3, int i4)
|
ref T opIndex(int i1, int i2, int i3, int i4)
|
||||||
{
|
{
|
||||||
if(dimCount != 4) throw new SyntaxError();
|
if(dimCount != 4) throw new SyntaxError();
|
||||||
if(i1 >= dim[0] && i2 >= dim[1] && i3 >= dim[2] && i4 >= dim[3]) throw new SubscriptOutOfRange();
|
if(i1 >= dim[0] && i2 >= dim[1] && i3 >= dim[2] && i4 >= dim[3]) throw new SubscriptOutOfRange();
|
||||||
|
|||||||
Reference in New Issue
Block a user