1
0

OUT関数を実装, 識別子に数字と_を認識するように修正

This commit is contained in:
otya128
2015-06-14 11:13:19 +09:00
parent b8a063f0a5
commit c71e84a7fc
6 changed files with 187 additions and 12 deletions

View File

@@ -770,6 +770,14 @@ class ReturnFunction : Code
{ {
vm.push(retexpr); vm.push(retexpr);
} }
else
{
//OUTの実装
for(int i = 0; i < func.outArgCount; i++)
{
vm.push(vm.stack[vm.bp + i + 2]);
}
}
vm.pc = pc.integerValue; vm.pc = pc.integerValue;
vm.bp = bp.integerValue; vm.bp = bp.integerValue;
} }
@@ -778,10 +786,18 @@ class CallFunctionCode : Code
{ {
wstring name; wstring name;
int argCount; int argCount;
int outArgCount;
this(wstring name, int argCount) this(wstring name, int argCount)
{ {
this.name = name; this.name = name;
this.argCount = argCount; this.argCount = argCount;
this.outArgCount = 1;
}
this(wstring name, int argCount, int outArgCount)
{
this.name = name;
this.argCount = argCount;
this.outArgCount = outArgCount;
} }
override void execute(VM vm) override void execute(VM vm)
{ {
@@ -794,6 +810,10 @@ class CallFunctionCode : Code
{ {
throw new IllegalFunctionCall(); throw new IllegalFunctionCall();
} }
if(func.outArgCount != this.outArgCount)
{
throw new IllegalFunctionCall();
}
//TODO:args //TODO:args
auto bp = vm.stacki; auto bp = vm.stacki;
vm.push(Value(vm.bp)); vm.push(Value(vm.bp));

View File

@@ -34,6 +34,7 @@ class Function
VMVariable[wstring] variable; VMVariable[wstring] variable;
int[wstring] label; int[wstring] label;
bool returnExpr; bool returnExpr;
int outArgCount;
this(int address, wstring name, bool returnExpr, int argCount) this(int address, wstring name, bool returnExpr, int argCount)
{ {
this.address = address; this.address = address;
@@ -41,6 +42,10 @@ class Function
this.returnExpr = returnExpr; this.returnExpr = returnExpr;
this.argCount = argCount; this.argCount = argCount;
this.variableIndex = 1;//0,bp,1,pc this.variableIndex = 1;//0,bp,1,pc
if(returnExpr)
{
outArgCount = 1;
}
} }
int getLocalVarIndex(wstring name, Compiler c) int getLocalVarIndex(wstring name, Compiler c)
{ {
@@ -72,6 +77,20 @@ class Function
} }
return var; return var;
} }
int defineLocalVarIndexVoid(wstring name, Compiler c)
{
int var = this.variable.get(name, VMVariable()).index;
if(var == 0)
{
this.variable[name] = VMVariable(var = ++variableIndex, ValueType.Void);
}
else
{
//error:二重定義
throw new DuplicateVariable();
}
return var;
}
int defineArgumentIndex(wstring name, Compiler c) int defineArgumentIndex(wstring name, Compiler c)
{ {
int var = this.variable.get(name, VMVariable()).index; int var = this.variable.get(name, VMVariable()).index;
@@ -224,7 +243,7 @@ class Compiler
{ {
if(sc.func) if(sc.func)
{ {
return sc.func.defineLocalVarIndex(name, this); return sc.func.defineLocalVarIndexVoid(name, this);
} }
int global = this.global.get(name, VMVariable()).index; int global = this.global.get(name, VMVariable()).index;
if(global == 0) if(global == 0)
@@ -447,7 +466,16 @@ class Compiler
{ {
func.defineArgumentIndex(arg, this); func.defineArgumentIndex(arg, this);
} }
foreach(wstring arg; node.outArguments)
{
func.defineLocalVarIndexVoid(arg, this);
}
if(!func.returnExpr)
func.outArgCount = node.outArguments.length;
compileStatements(node.functionBody, sc); compileStatements(node.functionBody, sc);
if(func.returnExpr)
genCodeImm(Value(ValueType.Void));
genCode(new ReturnFunction(func));
skip.address = this.code.length; skip.address = this.code.length;
this.functions[func.name] = func; this.functions[func.name] = func;
} }
@@ -528,8 +556,7 @@ class Compiler
} }
else else
{ {
//TODO:実装中 genCode(new ReturnFunction(s.func));
throw new SyntaxError();
} }
} }
} }
@@ -564,6 +591,21 @@ class Compiler
genCode(new PopArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length, !(s.func is null))); genCode(new PopArray(getGlobalVarIndex(assign.name), assign.indexExpression.expressions.length, !(s.func is null)));
} }
break; break;
case NodeType.CallFunctionStatement:
{
auto func = cast(CallFunctionStatement)i;
foreach_reverse(Expression j ; func.args)
{
compileExpression(j, s);
}
genCode(new CallFunctionCode(func.name, func.args.length, func.outVariable.length));
//TODO:OUT
foreach_reverse(wstring var; func.outVariable)
{
genCodePopVar(var, s);
}
}
break;
default: default:
stderr.writeln("Compile:NotImpl ", i.type); stderr.writeln("Compile:NotImpl ", i.type);
} }

View File

@@ -61,6 +61,12 @@ V[0,1]=12
GOSUB @A GOSUB @A
?A() ?A()
?B(1,2,3) ?B(1,2,3)
FOR I=0 TO 10
?I;\"!\",\"=\",FACT(I)
NEXT
TEST \"HELLO\",\",\",\"WORLD\"
TEST2 6,7,8 OUT K,L,M
?K,L,M
END END
@A @A
?\"SUBROUTINE TEST\" ?\"SUBROUTINE TEST\"
@@ -75,6 +81,19 @@ DEF B(A,B[],C)
?LOCAL ?LOCAL
RETURN -1 RETURN -1
END END
DEF FACT(N)
IF N<=1 THEN RETURN 1
RETURN N*FACT(N-1)
END
DEF TEST A,B,C
?\"TEST\",A,B,C
END
DEF TEST2 A,B,C OUT D,E,F
?\"TEST\",A,B,C
D=A
E=B
F=C
END
"); ");
version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring); version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring);
auto vm = parser.compile(); auto vm = parser.compile();

View File

@@ -388,3 +388,23 @@ class DefineFunction : Statement
this.outArguments ~= name; this.outArguments ~= name;
} }
} }
class CallFunctionStatement : Statement
{
wstring name;
Expression[] args;
wstring[] outVariable;
this(wstring n)
{
this.type = NodeType.CallFunctionStatement;
this.name = n;
args = new Expression[0];
}
void addArg(Expression arg)
{
args ~= arg;
}
void addOut(wstring var)
{
outVariable ~= var;
}
}

View File

@@ -59,6 +59,7 @@ class Lexical
reserved["VAR"] = TokenType.Var; reserved["VAR"] = TokenType.Var;
reserved["DIM"] = TokenType.Var; reserved["DIM"] = TokenType.Var;
reserved["DEF"] = TokenType.Def; reserved["DEF"] = TokenType.Def;
reserved["OUT"] = TokenType.Out;
reserved.rehash(); reserved.rehash();
line = 1; line = 1;
} }
@@ -104,7 +105,7 @@ class Lexical
for(;i < code.length;i++) for(;i < code.length;i++)
{ {
c = code[i]; c = code[i];
if(!c.isAlpha()) if(!c.isAlpha() && !c.isDigit() && c != '_')
{ {
break; break;
} }
@@ -420,7 +421,7 @@ class Parser
} }
return statements; return statements;
} }
bool isFunc = false; bool isFuncReturnExpr = false;
wstring getFunctionArgument() wstring getFunctionArgument()
{ {
auto token = lex.front(); auto token = lex.front();
@@ -490,15 +491,49 @@ class Parser
} }
else else
{ {
//MEMO:引数に[]を付けようが扱いは同一
while(true)
{
wstring arg = getFunctionArgument();
if(arg.length == 0)
{
return null;
}
node.addArgument(arg);
token = lex.front();
if(token.type == TokenType.Comma)
{
lex.popFront();
continue;
}
break;
}
if(token.type == TokenType.Out)
{
lex.popFront();
while(true)
{
wstring arg = getFunctionArgument();
if(arg.length == 0)
{
return null;
}
node.addOutArgument(arg);
token = lex.front();
if(token.type == TokenType.Comma)
{
lex.popFront();
continue;
}
break;
}
}
node.returnExpr = false; node.returnExpr = false;
//void関数にRETURN核とsyntaxerror //void関数にRETURN核とsyntaxerror
writeln("NOTIMPL:DEF VOID");
syntaxError();
return null;
} }
isFunc = true;//面倒くさい isFuncReturnExpr = node.returnExpr;//面倒くさい
node.functionBody = functionStatements(); node.functionBody = functionStatements();
isFunc = false; isFuncReturnExpr = false;
return node; return node;
} }
Statements functionStatements() Statements functionStatements()
@@ -601,6 +636,45 @@ class Parser
return node; return node;
} }
//命令呼び出し //命令呼び出し
auto func = new CallFunctionStatement(name);
node = func;
while(true)
{
token = lex.front();
if(token.type == TokenType.Comma)
{
func.addArg(new VoidExpression());
lex.popFront();
token = lex.front();
}
else
func.addArg(expression());
if(lex.front().type != TokenType.Comma) break;
lex.popFront();
}
if(lex.front().type == TokenType.Out)
{
lex.popFront();
while(true)
{
token = lex.front();
if(token.type != TokenType.Iden)
{
return null;
}
wstring arg = token.value.stringValue;
func.addOut(arg);
lex.popFront();
token = lex.front();
if(token.type == TokenType.Comma)
{
lex.popFront();
continue;
}
break;
}
}
} }
break; break;
case TokenType.Colon: case TokenType.Colon:
@@ -639,10 +713,9 @@ class Parser
break; break;
case TokenType.Return: case TokenType.Return:
lex.popFront(); lex.popFront();
if(isFunc) if(isFuncReturnExpr)
{ {
node = new Return(expression()); node = new Return(expression());
lex.popFront();
} }
else else
{ {

View File

@@ -53,6 +53,7 @@ enum TokenType
LBracket,//[ LBracket,//[
RBracket,//] RBracket,//]
Def, Def,
Out,
} }
struct Token struct Token