OUT関数を実装, 識別子に数字と_を認識するように修正
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
node.returnExpr = false;
|
//MEMO:引数に[]を付けようが扱いは同一
|
||||||
//void関数にRETURN核とsyntaxerror
|
while(true)
|
||||||
writeln("NOTIMPL:DEF VOID");
|
{
|
||||||
syntaxError();
|
wstring arg = getFunctionArgument();
|
||||||
|
if(arg.length == 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
isFunc = true;//面倒くさい
|
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;
|
||||||
|
//void関数にRETURN核とsyntaxerror
|
||||||
|
}
|
||||||
|
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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ enum TokenType
|
|||||||
LBracket,//[
|
LBracket,//[
|
||||||
RBracket,//]
|
RBracket,//]
|
||||||
Def,
|
Def,
|
||||||
|
Out,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
|
|||||||
Reference in New Issue
Block a user