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.type;
import otya.smilebasic.token; import otya.smilebasic.token;
import otya.smilebasic.error; import otya.smilebasic.error;
import otya.smilebasic.compiler;
import std.uni; import std.uni;
import std.utf; import std.utf;
import std.conv; import std.conv;
@@ -14,6 +15,7 @@ class VM
Value[] stack; Value[] stack;
Value[] global; Value[] global;
int[wstring] globalTable; int[wstring] globalTable;
Function[wstring] functions;
int bp; int bp;
ValueType getType(wstring name) ValueType getType(wstring name)
{ {
@@ -30,7 +32,7 @@ class VM
return ValueType.Double;//DEFINT時 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.code = code;
this.stack = new Value[16384]; this.stack = new Value[16384];
@@ -40,6 +42,7 @@ class VM
{ {
this.global[v] = Value(getType(k)); this.global[v] = Value(getType(k));
} }
this.functions = functions;
} }
void run() void run()
{ {
@@ -684,3 +687,49 @@ class PopGArray : Code
throw new TypeMismatch(); 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 breakAddr;
GotoAddr continueAddr; GotoAddr continueAddr;
Function func;
this() this()
{ {
} }
@@ -17,19 +18,28 @@ class Scope
this.breakAddr = breakAddr; this.breakAddr = breakAddr;
this.continueAddr = continueAddr; this.continueAddr = continueAddr;
} }
this(Function func)
{
this.func = func;
}
} }
class Function class Function
{ {
int address; int address;
wstring name; wstring name;
int argCount;
int argumentIndex; int argumentIndex;
int variableIndex; int variableIndex;
int[wstring] variable; int[wstring] variable;
int[wstring] label; int[wstring] label;
this(int address, wstring name) bool returnExpr;
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.argCount = argCount;
this.variableIndex = 1;//0,bp,1,pc
} }
int getLocalVarIndex(wstring name) int getLocalVarIndex(wstring name)
{ {
@@ -56,6 +66,20 @@ class Function
} }
return var; 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 class Compiler
{ {
@@ -165,7 +189,11 @@ class Compiler
} }
void compileExpression(Expression exp) void compileExpression(Expression exp)
{ {
if(!exp)
{
genCodeImm(Value(ValueType.Void));
return;
}
switch(exp.type) switch(exp.type)
{ {
case NodeType.Constant: case NodeType.Constant:
@@ -206,13 +234,11 @@ class Compiler
case NodeType.CallFunction: case NodeType.CallFunction:
{ {
auto func = cast(CallFunction)exp; 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; break;
case NodeType.IndexExpressions://[expr,expr,expr,expr]用 case NodeType.IndexExpressions://[expr,expr,expr,expr]用
@@ -333,6 +359,19 @@ class Compiler
compileStatement(s, sc); 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) void compileStatement(Statement i, Scope s)
{ {
switch(i.type) switch(i.type)
@@ -393,11 +432,26 @@ class Compiler
case NodeType.Return: case NodeType.Return:
{ {
auto ret = cast(Return)i; auto ret = cast(Return)i;
if(s.func is null)
{
if(ret.expression is null) if(ret.expression is null)
genCode(new ReturnSubroutine()); genCode(new ReturnSubroutine());
else
throw new SyntaxError();
}
else else
{ {
//関数未実装:error //値を返せる関数
if(s.func.returnExpr)
{
compileExpression(ret.expression);
genCode(new ReturnFunction(s.func));
}
else
{
//TODO:実装中
throw new SyntaxError();
}
} }
} }
break; break;
@@ -440,6 +494,11 @@ class Compiler
Scope s = new Scope(); Scope s = new Scope();
foreach(Statement i ; statements.statements) foreach(Statement i ; statements.statements)
{ {
if(i.type == NodeType.DefineFunction)
{
compileDefineFunction(cast(DefineFunction)i);
continue;
}
compileStatement(i, s); compileStatement(i, s);
} }
foreach(int i, Code c; code) foreach(int i, Code c; code)
@@ -453,7 +512,7 @@ class Compiler
code[i] = new GosubAddr(globalLabel[(cast(GosubS)c).label]); 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"); super("Syntax error");
} }
} }
class IllegalFunctionCall : SmileBasicError
{
this()
{
this.errnum = 4;
super("Illegal function call");
}
}
class TypeMismatch : SmileBasicError class TypeMismatch : SmileBasicError
{ {
this() this()

View File

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

View File

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

View File

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