1
0

とりあえず関数呼び出し

This commit is contained in:
otya128
2015-06-13 20:21:11 +09:00
parent 4b530f492e
commit dec42422b5
6 changed files with 160 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ module otya.smilebasic.vm;
import otya.smilebasic.type;
import otya.smilebasic.token;
import otya.smilebasic.error;
import otya.smilebasic.compiler;
import std.uni;
import std.utf;
import std.conv;
@@ -14,6 +15,7 @@ class VM
Value[] stack;
Value[] global;
int[wstring] globalTable;
Function[wstring] functions;
int bp;
ValueType getType(wstring name)
{
@@ -30,7 +32,7 @@ class VM
return ValueType.Double;//DEFINT時
}
}
this(Code[] code, int len, int[wstring] globalTable)
this(Code[] code, int len, int[wstring] globalTable, Function[wstring] functions)
{
this.code = code;
this.stack = new Value[16384];
@@ -40,6 +42,7 @@ class VM
{
this.global[v] = Value(getType(k));
}
this.functions = functions;
}
void run()
{
@@ -684,3 +687,49 @@ class PopGArray : Code
throw new TypeMismatch();
}
}
class ReturnFunction : Code
{
Function func;
this(Function func)
{
this.func = func;
}
override void execute(VM vm)
{
int oldstacki = vm.stacki;
vm.stacki = vm.bp + 2;
Value bp, pc;
vm.pop(pc);
vm.pop(bp);
vm.push(Value(235));
vm.pc = pc.integerValue;
vm.bp = bp.integerValue;
}
}
class CallFunctionCode : Code
{
wstring name;
int argCount;
this(wstring name, int argCount)
{
this.name = name;
this.argCount = argCount;
}
override void execute(VM vm)
{
Function func = vm.functions[name];
if(!func)
{
throw new SyntaxError();
}
if(func.argCount != this.argCount)
{
throw new IllegalFunctionCall();
}
//TODO:args
vm.push(Value(vm.bp));
vm.push(Value(vm.pc));
vm.bp = vm.stacki - 2;
vm.pc = func.address - 1;
}
}

View File

@@ -9,6 +9,7 @@ class Scope
{
GotoAddr breakAddr;
GotoAddr continueAddr;
Function func;
this()
{
}
@@ -17,19 +18,28 @@ class Scope
this.breakAddr = breakAddr;
this.continueAddr = continueAddr;
}
this(Function func)
{
this.func = func;
}
}
class Function
{
int address;
wstring name;
int argCount;
int argumentIndex;
int variableIndex;
int[wstring] variable;
int[wstring] label;
this(int address, wstring name)
bool returnExpr;
this(int address, wstring name, bool returnExpr, int argCount)
{
this.address = address;
this.name = name;
this.returnExpr = returnExpr;
this.argCount = argCount;
this.variableIndex = 1;//0,bp,1,pc
}
int getLocalVarIndex(wstring name)
{
@@ -56,6 +66,20 @@ class Function
}
return var;
}
int defineArgumentIndex(wstring name)
{
int var = this.variable.get(name, 0);
if(var == 0)
{
this.variable[name] = var = ++variableIndex;
}
else
{
//error:二重定義
//TODO:3.1ではエラーにならない
}
return var;
}
}
class Compiler
{
@@ -165,7 +189,11 @@ class Compiler
}
void compileExpression(Expression exp)
{
if(!exp)
{
genCodeImm(Value(ValueType.Void));
return;
}
switch(exp.type)
{
case NodeType.Constant:
@@ -206,13 +234,11 @@ class Compiler
case NodeType.CallFunction:
{
auto func = cast(CallFunction)exp;
if(func.name == "ADD")
foreach_reverse(Expression i ; func.args)
{
foreach_reverse(Expression i ; func.args)
{
compileExpression(i);
}
compileExpression(i);
}
genCode(new CallFunctionCode(func.name, func.args.length));
}
break;
case NodeType.IndexExpressions://[expr,expr,expr,expr]用
@@ -333,6 +359,19 @@ class Compiler
compileStatement(s, sc);
}
}
void compileDefineFunction(DefineFunction node)
{
auto skip = genCodeGoto();
Function func = new Function(this.code.length, node.name, node.returnExpr, node.arguments.length);
Scope sc = new Scope(func);
foreach(wstring arg; node.arguments)
{
func.defineArgumentIndex(arg);
}
compileStatements(node.functionBody, sc);
skip.address = this.code.length;
this.functions[func.name] = func;
}
void compileStatement(Statement i, Scope s)
{
switch(i.type)
@@ -393,11 +432,26 @@ class Compiler
case NodeType.Return:
{
auto ret = cast(Return)i;
if(ret.expression is null)
genCode(new ReturnSubroutine());
if(s.func is null)
{
if(ret.expression is null)
genCode(new ReturnSubroutine());
else
throw new SyntaxError();
}
else
{
//関数未実装:error
//値を返せる関数
if(s.func.returnExpr)
{
compileExpression(ret.expression);
genCode(new ReturnFunction(s.func));
}
else
{
//TODO:実装中
throw new SyntaxError();
}
}
}
break;
@@ -440,6 +494,11 @@ class Compiler
Scope s = new Scope();
foreach(Statement i ; statements.statements)
{
if(i.type == NodeType.DefineFunction)
{
compileDefineFunction(cast(DefineFunction)i);
continue;
}
compileStatement(i, s);
}
foreach(int i, Code c; code)
@@ -453,7 +512,7 @@ class Compiler
code[i] = new GosubAddr(globalLabel[(cast(GosubS)c).label]);
}
}
return new VM(code, globalIndex + 1, global);
return new VM(code, globalIndex + 1, global, functions);
}
}

View File

@@ -27,6 +27,14 @@ class SyntaxError : SmileBasicError
super("Syntax error");
}
}
class IllegalFunctionCall : SmileBasicError
{
this()
{
this.errnum = 4;
super("Illegal function call");
}
}
class TypeMismatch : SmileBasicError
{
this()

View File

@@ -59,15 +59,18 @@ V[0,1]=12
?\"ABC\"[1][0]
?1/2
GOSUB @A
?A()
END
@A
?\"SUBROUTINE TEST\"
RETURN
DEF A()
?\"FUNCTION A\"
RETURN 1
END
DEF B(A,B[],C)
?\"FUNCTION B\"
RETURN 0
END
");
version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring);
@@ -80,6 +83,10 @@ END
{
writeln(sbe);
}
catch(Throwable t)
{
writeln(t);
}
readln();
return 0;
}

View File

@@ -366,10 +366,18 @@ class DefineFunction : Statement
wstring[] outArguments;
wstring name;
Statements functionBody;
bool returnExpr;
this(wstring name, bool returnExpr)
{
this.type = NodeType.DefineFunction;
this.name = name;
this.returnExpr = returnExpr;
}
this(wstring name)
{
this.type = NodeType.DefineFunction;
this.name = name;
this.returnExpr = false;
}
void addArgument(wstring name)
{

View File

@@ -420,6 +420,7 @@ class Parser
}
return statements;
}
bool isFunc = false;
wstring getFunctionArgument()
{
auto token = lex.front();
@@ -455,6 +456,7 @@ class Parser
token = lex.front();
if(token.type == TokenType.LParen)
{
node.returnExpr = true;
lex.popFront();
//MEMO:引数に[]を付けようが扱いは同一
while(true)
@@ -488,12 +490,15 @@ class Parser
}
else
{
node.returnExpr = false;
//void関数にRETURN核とsyntaxerror
writeln("NOTIMPL:DEF VOID");
syntaxError();
return null;
}
isFunc = true;//面倒くさい
node.functionBody = functionStatements();
isFunc = false;
return node;
}
Statements functionStatements()
@@ -634,7 +639,15 @@ class Parser
break;
case TokenType.Return:
lex.popFront();
node = new Return(expression());
if(isFunc)
{
node = new Return(expression());
lex.popFront();
}
else
{
node = new Return(null);
}
return node;
case TokenType.End:
node = new End();
@@ -1014,6 +1027,7 @@ class Parser
lex.popFront();
token = lex.front();
if(token.type == TokenType.RParen) break;
if(token.type == TokenType.Comma)
{
func.addArg(new VoidExpression());
@@ -1021,7 +1035,7 @@ class Parser
token = lex.front();
}
else
func.addArg(expression());
func.addArg(expression());
if(lex.front().type == TokenType.RParen) break;
}
}