1
0

ローカル変数の参照,定義を実�

This commit is contained in:
otya128
2015-06-13 21:35:28 +09:00
parent f1ecd08462
commit b8a063f0a5
3 changed files with 223 additions and 79 deletions

View File

@@ -7,6 +7,16 @@ import std.uni;
import std.utf; import std.utf;
import std.conv; import std.conv;
import std.stdio; import std.stdio;
struct VMVariable
{
int index;
ValueType type;
this(int index, ValueType type)
{
this.index = index;
this.type = type;
}
}
class VM class VM
{ {
Code[] code; Code[] code;
@@ -14,33 +24,18 @@ class VM
int pc; int pc;
Value[] stack; Value[] stack;
Value[] global; Value[] global;
int[wstring] globalTable; VMVariable[wstring] globalTable;
Function[wstring] functions; Function[wstring] functions;
int bp; int bp;
ValueType getType(wstring name) this(Code[] code, int len, VMVariable[wstring] globalTable, Function[wstring] functions)
{
wchar s = name[name.length - 1];
switch(s)
{
case '$':
return ValueType.String;
case '#':
return ValueType.Double;
case '%':
return ValueType.Integer;
default:
return ValueType.Double;//DEFINT時
}
}
this(Code[] code, int len, int[wstring] globalTable, Function[wstring] functions)
{ {
this.code = code; this.code = code;
this.stack = new Value[16384]; this.stack = new Value[16384];
this.global = new Value[len]; this.global = new Value[len];
this.globalTable = globalTable; this.globalTable = globalTable;
foreach(wstring k, int v ; globalTable) foreach(wstring k, VMVariable v ; globalTable)
{ {
this.global[v] = Value(getType(k)); this.global[v.index] = Value(v.type);
} }
this.functions = functions; this.functions = functions;
} }
@@ -79,7 +74,7 @@ class VM
} }
Value testGetGlobalVariable(wstring name) Value testGetGlobalVariable(wstring name)
{ {
return global[globalTable[name]]; return global[globalTable[name].index];
} }
void end() void end()
{ {
@@ -90,12 +85,14 @@ enum CodeType
{ {
Push, Push,
PushG, PushG,
PushL,
Operate, Operate,
Return, Return,
Goto, Goto,
Gosub, Gosub,
Print, Print,
PopG, PopG,
PopL,
GotoS, GotoS,
GotoFalse, GotoFalse,
GotoTrue, GotoTrue,
@@ -193,7 +190,7 @@ class PopG : Code
vm.global[var] = Value(cast(int)v.doubleValue); vm.global[var] = Value(cast(int)v.doubleValue);
return; return;
} }
if(v.type == ValueType.Void) if(g.type == ValueType.Void)
{ {
vm.global[var] = v; vm.global[var] = v;
return; return;
@@ -205,6 +202,54 @@ class PopG : Code
vm.global[var] = v; vm.global[var] = v;
} }
} }
class PushL : Code
{
int var;
this(int var)
{
this.type = CodeType.PushL;
this.var = var;
}
override void execute(VM vm)
{
vm.push(vm.stack[vm.bp + var]);
}
}
class PopL : Code
{
int var;
this(int var)
{
this.type = CodeType.PopL;
this.var = var;
}
override void execute(VM vm)
{
Value v;
Value g = vm.stack[vm.bp + var];
vm.pop(v);
if(v.type == ValueType.Integer && g.type == ValueType.Double)
{
vm.stack[vm.bp + var] = Value(cast(double)v.integerValue);
return;
}
if(g.type == ValueType.Integer && v.type == ValueType.Double)
{
vm.stack[vm.bp + var] = Value(cast(int)v.doubleValue);
return;
}
if(g.type == ValueType.Void)
{
vm.stack[vm.bp + var] = v;
return;
}
if(v.type != g.type)
{
throw new TypeMismatch();
}
vm.stack[vm.bp + var] = v;
}
}
class Operate : Code class Operate : Code
{ {
TokenType operator; TokenType operator;
@@ -518,15 +563,13 @@ class EndVM : Code
class NewArray : Code class NewArray : Code
{ {
ValueType type; ValueType type;
int index;
int size; int size;
int[] dim; int[] dim;
this(ValueType type, int size, int index) this(ValueType type, int size)
{ {
dim = new int[size]; dim = new int[size];
this.size = size; this.size = size;
this.type = type; this.type = type;
this.index = index;
} }
override void execute(VM vm) override void execute(VM vm)
{ {
@@ -546,24 +589,26 @@ class NewArray : Code
} }
throw new TypeMismatch(); throw new TypeMismatch();
} }
Value array;
switch(type) switch(type)
{ {
case ValueType.Integer: case ValueType.Integer:
vm.global[index].type = ValueType.IntegerArray; array.type = ValueType.IntegerArray;
vm.global[index].integerArray = new Array!int(dim); array.integerArray = new Array!int(dim);
break; break;
case ValueType.Double: case ValueType.Double:
vm.global[index].type = ValueType.DoubleArray; array.type = ValueType.DoubleArray;
vm.global[index].doubleArray = new Array!double(dim); array.doubleArray = new Array!double(dim);
break; break;
case ValueType.String: case ValueType.String:
vm.global[index].type = ValueType.StringArray; array.type = ValueType.StringArray;
vm.global[index].stringArray = new Array!wstring(dim); array.stringArray = new Array!wstring(dim);
break; break;
default: default:
throw new TypeMismatch(); throw new TypeMismatch();
break; break;
} }
vm.push(array);
} }
} }
class PushArray : Code class PushArray : Code
@@ -626,18 +671,28 @@ class PushArray : Code
throw new TypeMismatch(); throw new TypeMismatch();
} }
} }
class PopGArray : Code class PopArray : Code
{ {
int var; int var;
int dim; int dim;
this(int var, int dim) bool local;
this(int var, int dim, bool local)
{ {
this.var = var; this.var = var;
this.dim = dim; this.dim = dim;
this.local = local;
} }
override void execute(VM vm) override void execute(VM vm)
{ {
Value array = vm.global[var]; Value array;
if(local)
{
array = vm.stack[vm.bp + var];
}
else
{
array = vm.global[var];
}
if(!array.isArray) if(!array.isArray)
{ {
throw new TypeMismatch(); throw new TypeMismatch();
@@ -745,5 +800,13 @@ class CallFunctionCode : Code
vm.push(Value(vm.pc)); 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;
foreach(wstring k, VMVariable v ; func.variable)
{
if(v.index > 0)
{
vm.stack[bp + v.index] = Value(v.type);
}
}
} }
} }

View File

@@ -13,10 +13,11 @@ class Scope
this() this()
{ {
} }
this(GotoAddr breakAddr, GotoAddr continueAddr) this(GotoAddr breakAddr, GotoAddr continueAddr, Scope parent)
{ {
this.breakAddr = breakAddr; this.breakAddr = breakAddr;
this.continueAddr = continueAddr; this.continueAddr = continueAddr;
this.func = parent.func;
} }
this(Function func) this(Function func)
{ {
@@ -30,7 +31,7 @@ class Function
int argCount; int argCount;
int argumentIndex; int argumentIndex;
int variableIndex; int variableIndex;
int[wstring] variable; VMVariable[wstring] variable;
int[wstring] label; int[wstring] label;
bool returnExpr; bool returnExpr;
this(int address, wstring name, bool returnExpr, int argCount) this(int address, wstring name, bool returnExpr, int argCount)
@@ -41,23 +42,28 @@ class Function
this.argCount = argCount; this.argCount = argCount;
this.variableIndex = 1;//0,bp,1,pc this.variableIndex = 1;//0,bp,1,pc
} }
int getLocalVarIndex(wstring name) int getLocalVarIndex(wstring name, Compiler c)
{ {
int var = this.variable.get(name, 0); int var = this.variable.get(name, VMVariable()).index;
if(var == 0) if(var == 0)
{ {
//local変数をあたる //local変数をあたる
//それでもだめならOPTION STRICTならエラー //それでもだめならOPTION STRICTならエラー
this.variable[name] = var = ++variableIndex; this.variable[name] = VMVariable(var = ++variableIndex, c.getType(name));
} }
return var; return var;
} }
int defineLocalVarIndex(wstring name) int hasLocalVarIndex(wstring name)
{ {
int var = this.variable.get(name, 0); int var = this.variable.get(name, VMVariable()).index;
return var;
}
int defineLocalVarIndex(wstring name, Compiler c)
{
int var = this.variable.get(name, VMVariable()).index;
if(var == 0) if(var == 0)
{ {
this.variable[name] = var = ++variableIndex; this.variable[name] = VMVariable(var = ++variableIndex, c.getType(name));
} }
else else
{ {
@@ -66,12 +72,12 @@ class Function
} }
return var; return var;
} }
int defineArgumentIndex(wstring name) int defineArgumentIndex(wstring name, Compiler c)
{ {
int var = this.variable.get(name, 0); int var = this.variable.get(name, VMVariable()).index;
if(var == 0) if(var == 0)
{ {
this.variable[name] = var = --argumentIndex; this.variable[name] = VMVariable(var = --argumentIndex, c.getType(name));
} }
else else
{ {
@@ -106,7 +112,7 @@ class Compiler
} }
Code[] code; Code[] code;
int[wstring] global; VMVariable[wstring] global;
int[wstring] globalLabel; int[wstring] globalLabel;
Function[wstring] functions; Function[wstring] functions;
int globalIndex = 0; int globalIndex = 0;
@@ -126,6 +132,36 @@ class Compiler
{ {
code ~= new PopG(ind); code ~= new PopG(ind);
} }
void genCodePushVar(wstring name, Scope sc)
{
auto global = hasGlobalVarIndex(name);
if(global)
{
code ~= new PushG(global);
return;
}
if(sc.func)
{
code ~= new PushL(sc.func.getLocalVarIndex(name, this));
return;
}
code ~= new PushG(getGlobalVarIndex(name));
}
void genCodePopVar(wstring name, Scope sc)
{
auto global = hasGlobalVarIndex(name);
if(global)
{
code ~= new PopG(global);
return;
}
if(sc.func)
{
code ~= new PopL(sc.func.getLocalVarIndex(name, this));
return;
}
code ~= new PopG(getGlobalVarIndex(name));
}
void genCodeOP(TokenType op) void genCodeOP(TokenType op)
{ {
code ~= new Operate(op); code ~= new Operate(op);
@@ -164,10 +200,36 @@ class Compiler
} }
int defineGlobalVarIndex(wstring name) int defineGlobalVarIndex(wstring name)
{ {
int global = this.global.get(name, 0); int global = this.global.get(name, VMVariable()).index;
if(global == 0) if(global == 0)
{ {
this.global[name] = global = ++globalIndex; this.global[name] = VMVariable(global = ++globalIndex, getType(name));
}
else
{
//error:二重定義
throw new DuplicateVariable();
}
return global;
}
int defineVarIndex(wstring name, Scope sc)
{
if(sc.func)
{
return sc.func.defineLocalVarIndex(name, this);
}
return defineGlobalVarIndex(name);
}
int defineVarIndexVoid(wstring name, Scope sc)
{
if(sc.func)
{
return sc.func.defineLocalVarIndex(name, this);
}
int global = this.global.get(name, VMVariable()).index;
if(global == 0)
{
this.global[name] = VMVariable(global = ++globalIndex, ValueType.Void);
} }
else else
{ {
@@ -178,16 +240,32 @@ class Compiler
} }
int getGlobalVarIndex(wstring name) int getGlobalVarIndex(wstring name)
{ {
int global = this.global.get(name, 0); int global = this.global.get(name, VMVariable()).index;
if(global == 0) if(global == 0)
{ {
//local変数をあたる //local変数をあたる
//それでもだめならOPTION STRICTならエラー //それでもだめならOPTION STRICTならエラー
this.global[name] = global = ++globalIndex; this.global[name] = VMVariable(global = ++globalIndex, getType(name));
} }
return global; return global;
} }
void compileExpression(Expression exp) int hasGlobalVarIndex(wstring name)
{
int global = this.global.get(name, VMVariable()).index;
return global;
}
int getLocalVarIndex(wstring name, Scope sc)
{
if(sc.func)
{
int global = hasGlobalVarIndex(name);
if(global) return global;
int local = sc.func.getLocalVarIndex(name, this);
return local;
}
return 0;
}
void compileExpression(Expression exp, Scope sc)
{ {
if(!exp) if(!exp)
{ {
@@ -202,8 +280,8 @@ class Compiler
case NodeType.BinaryOperator: case NodeType.BinaryOperator:
{ {
auto binop = cast(BinaryOperator)exp; auto binop = cast(BinaryOperator)exp;
compileExpression(binop.item1); compileExpression(binop.item1, sc);
compileExpression(binop.item2); compileExpression(binop.item2, sc);
if(binop.operator == TokenType.LBracket) if(binop.operator == TokenType.LBracket)
{ {
IndexExpressions ie = cast(IndexExpressions)binop.item2; IndexExpressions ie = cast(IndexExpressions)binop.item2;
@@ -223,20 +301,20 @@ class Compiler
case NodeType.UnaryOperator: case NodeType.UnaryOperator:
{ {
auto una = cast(UnaryOperator)exp; auto una = cast(UnaryOperator)exp;
compileExpression(una.item); compileExpression(una.item, sc);
genCodeOP(una.operator); genCodeOP(una.operator);
} }
break; break;
case NodeType.Variable: case NodeType.Variable:
auto var = cast(Variable)exp; auto var = cast(Variable)exp;
genCodePushGlobal(getGlobalVarIndex(var.name)); genCodePushVar(var.name, sc);
break; break;
case NodeType.CallFunction: case NodeType.CallFunction:
{ {
auto func = cast(CallFunction)exp; auto func = cast(CallFunction)exp;
foreach_reverse(Expression i ; func.args) foreach_reverse(Expression i ; func.args)
{ {
compileExpression(i); compileExpression(i, sc);
} }
genCode(new CallFunctionCode(func.name, func.args.length)); genCode(new CallFunctionCode(func.name, func.args.length));
} }
@@ -247,7 +325,7 @@ class Compiler
int count = 0; int count = 0;
foreach_reverse(Expression i; index.expressions) foreach_reverse(Expression i; index.expressions)
{ {
compileExpression(i); compileExpression(i, sc);
count++; count++;
if(count >= 4) break;//念のため if(count >= 4) break;//念のため
} }
@@ -260,7 +338,7 @@ class Compiler
} }
void compileIf(If node, Scope sc) void compileIf(If node, Scope sc)
{ {
compileExpression(node.condition); compileExpression(node.condition, sc);
//条件式がfalseならendif or elseに飛ぶ //条件式がfalseならendif or elseに飛ぶ
auto else_ = genCodeGotoFalse(); auto else_ = genCodeGotoFalse();
compileStatements(node.then, sc); compileStatements(node.then, sc);
@@ -283,7 +361,7 @@ class Compiler
{ {
compileStatement(node.initExpression, s); compileStatement(node.initExpression, s);
auto forstart = code.length; auto forstart = code.length;
compileExpression(node.stepExpression); compileExpression(node.stepExpression, s);
genCodeImm(Value(0)); genCodeImm(Value(0));
//step>=0 //step>=0
genCodeOP(TokenType.GreaterEqual); genCodeOP(TokenType.GreaterEqual);
@@ -296,8 +374,8 @@ class Compiler
//FOR I=0 TO -1 STEP -1 //FOR I=0 TO -1 STEP -1
//-1>0 false //-1>0 false
//1>0 true //1>0 true
compileExpression(node.toExpression); compileExpression(node.toExpression, s);
genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); genCodePushVar(node.initExpression.name, s);
genCodeOP(TokenType.Greater); genCodeOP(TokenType.Greater);
auto breakAddr = genCodeGotoTrue(); auto breakAddr = genCodeGotoTrue();
auto forAddr = genCodeGoto(); auto forAddr = genCodeGoto();
@@ -308,19 +386,19 @@ class Compiler
//0<0 false //0<0 false
//1<0 false //1<0 false
//0<1 true break //0<1 true break
compileExpression(node.toExpression); compileExpression(node.toExpression, s);
genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); genCodePushVar(node.initExpression.name, s);
genCodeOP(TokenType.Less); genCodeOP(TokenType.Less);
genCode(breakAddr); genCode(breakAddr);
forAddr.address = code.length; forAddr.address = code.length;
s = new Scope(new GotoAddr(-1), new GotoAddr(-1)); s = new Scope(new GotoAddr(-1), new GotoAddr(-1), s);
compileStatements(node.statements, s); compileStatements(node.statements, s);
s.continueAddr.address = code.length; s.continueAddr.address = code.length;
//counterに加算する //counterに加算する
genCodePushGlobal(getGlobalVarIndex(node.initExpression.name)); genCodePushVar(node.initExpression.name, s);
compileExpression(node.stepExpression); compileExpression(node.stepExpression, s);
genCodeOP(TokenType.Plus); genCodeOP(TokenType.Plus);
genCodePopGlobal(getGlobalVarIndex(node.initExpression.name)); genCodePopVar(node.initExpression.name, s);
genCodeGoto(forstart); genCodeGoto(forstart);
breakAddr.address = code.length; breakAddr.address = code.length;
s.breakAddr.address = code.length; s.breakAddr.address = code.length;
@@ -332,8 +410,7 @@ class Compiler
if(v.type == NodeType.DefineVariable) if(v.type == NodeType.DefineVariable)
{ {
DefineVariable var = cast(DefineVariable)v; DefineVariable var = cast(DefineVariable)v;
//TODO:local variable defineVarIndex(var.name, sc);
defineGlobalVarIndex(var.name);
continue; continue;
} }
if(v.type == NodeType.DefineArray) if(v.type == NodeType.DefineArray)
@@ -342,12 +419,14 @@ class Compiler
int siz = 0; int siz = 0;
foreach_reverse(Expression expr; var.dim.expressions) foreach_reverse(Expression expr; var.dim.expressions)
{ {
compileExpression(expr); compileExpression(expr, sc);
siz++; siz++;
if(siz == 4) if(siz == 4)
break;//4次元まで(パーサーで除去するけど万が一に備えて break;//4次元まで(パーサーで除去するけど万が一に備えて
} }
genCode(new NewArray(getType(var.name), var.dim.expressions.length, defineGlobalVarIndex(var.name))); defineVarIndexVoid(var.name, sc);
genCode(new NewArray(getType(var.name), var.dim.expressions.length));
genCodePopVar(var.name, sc);
continue; continue;
} }
} }
@@ -366,7 +445,7 @@ class Compiler
Scope sc = new Scope(func); Scope sc = new Scope(func);
foreach(wstring arg; node.arguments) foreach(wstring arg; node.arguments)
{ {
func.defineArgumentIndex(arg); func.defineArgumentIndex(arg, this);
} }
compileStatements(node.functionBody, sc); compileStatements(node.functionBody, sc);
skip.address = this.code.length; skip.address = this.code.length;
@@ -384,7 +463,7 @@ class Compiler
switch(j.type) switch(j.type)
{ {
case PrintArgumentType.Expression: case PrintArgumentType.Expression:
compileExpression(j.expression); compileExpression(j.expression, s);
break; break;
case PrintArgumentType.Line: case PrintArgumentType.Line:
genCodeImm(Value("\n")); genCodeImm(Value("\n"));
@@ -402,8 +481,8 @@ class Compiler
case NodeType.Assign: case NodeType.Assign:
{ {
auto assign = cast(Assign)i; auto assign = cast(Assign)i;
compileExpression(assign.expression); compileExpression(assign.expression, s);
genCodePopGlobal(getGlobalVarIndex(assign.name)); genCodePopVar(assign.name, s);
} }
break; break;
case NodeType.Label: case NodeType.Label:
@@ -444,7 +523,7 @@ class Compiler
//値を返せる関数 //値を返せる関数
if(s.func.returnExpr) if(s.func.returnExpr)
{ {
compileExpression(ret.expression); compileExpression(ret.expression, s);
genCode(new ReturnFunction(s.func)); genCode(new ReturnFunction(s.func));
} }
else else
@@ -480,9 +559,9 @@ class Compiler
case NodeType.ArrayAssign: case NodeType.ArrayAssign:
{ {
auto assign = cast(ArrayAssign)i; auto assign = cast(ArrayAssign)i;
compileExpression(assign.assignExpression); compileExpression(assign.assignExpression, s);
compileExpression(assign.indexExpression); compileExpression(assign.indexExpression, s);
genCode(new PopGArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length)); genCode(new PopArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length, !(s.func is null)));
} }
break; break;
default: default:

View File

@@ -70,7 +70,9 @@ DEF A()
RETURN 1 RETURN 1
END END
DEF B(A,B[],C) DEF B(A,B[],C)
?\"FUNCTION B\" LOCAL=123
?\"FUNCTION B\",A,B,C
?LOCAL
RETURN -1 RETURN -1
END END
"); ");