GOSUB実�
This commit is contained in:
@@ -32,7 +32,7 @@ class VM
|
||||
this(Code[] code, int len, int[wstring] globalTable)
|
||||
{
|
||||
this.code = code;
|
||||
this.stack = new Value[1024 * 1024];
|
||||
this.stack = new Value[16384];
|
||||
this.global = new Value[len];
|
||||
this.globalTable = globalTable;
|
||||
foreach(wstring k, int v ; globalTable)
|
||||
@@ -68,6 +68,10 @@ class VM
|
||||
{
|
||||
return global[globalTable[name]];
|
||||
}
|
||||
void end()
|
||||
{
|
||||
pc = code.length;
|
||||
}
|
||||
}
|
||||
enum CodeType
|
||||
{
|
||||
@@ -82,6 +86,8 @@ enum CodeType
|
||||
GotoS,
|
||||
GotoFalse,
|
||||
GotoTrue,
|
||||
GosubS,
|
||||
ReturnSubroutine,
|
||||
}
|
||||
abstract class Code
|
||||
{
|
||||
@@ -420,7 +426,60 @@ class GotoFalse : Code
|
||||
vm.pc = address - 1;
|
||||
}
|
||||
}
|
||||
class Gosub : Code
|
||||
class GosubAddr : Code
|
||||
{
|
||||
|
||||
int address;
|
||||
this(int addr)
|
||||
{
|
||||
this.type = CodeType.Gosub;
|
||||
address = addr;
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.push(Value(vm.pc));
|
||||
vm.pc = address - 1;
|
||||
}
|
||||
}
|
||||
class GosubS : Code
|
||||
{
|
||||
wstring label;
|
||||
this(wstring label)
|
||||
{
|
||||
this.type = CodeType.GosubS;
|
||||
this.label = label;
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
stderr.writeln("can't execute");
|
||||
}
|
||||
}
|
||||
class ReturnSubroutine : Code
|
||||
{
|
||||
this()
|
||||
{
|
||||
this.type = CodeType.ReturnSubroutine;
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
Value pc;
|
||||
vm.pop(pc);
|
||||
if(pc.type != ValueType.Integer || pc.integerValue < 0 || pc.integerValue >= vm.code.length)
|
||||
{
|
||||
stderr.writeln("Internal error:Compiler bug?");
|
||||
readln();
|
||||
return;
|
||||
}
|
||||
vm.pc = pc.integerValue;
|
||||
}
|
||||
}
|
||||
class EndVM : Code
|
||||
{
|
||||
this()
|
||||
{
|
||||
}
|
||||
override void execute(VM vm)
|
||||
{
|
||||
vm.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,10 @@ class Compiler
|
||||
{
|
||||
code ~= new GotoS(label);
|
||||
}
|
||||
void genCodeGosub(wstring label)
|
||||
{
|
||||
code ~= new GosubS(label);
|
||||
}
|
||||
GotoAddr genCodeGoto()
|
||||
{
|
||||
auto c = new GotoAddr(-1);
|
||||
@@ -258,6 +262,26 @@ class Compiler
|
||||
case NodeType.For:
|
||||
compileFor(cast(For)i);
|
||||
break;
|
||||
case NodeType.Gosub:
|
||||
{
|
||||
auto gosub = cast(Gosub)i;
|
||||
genCodeGosub(gosub.label);
|
||||
}
|
||||
break;
|
||||
case NodeType.Return:
|
||||
{
|
||||
auto ret = cast(Return)i;
|
||||
if(ret.expression is null)
|
||||
genCode(new ReturnSubroutine());
|
||||
else
|
||||
{
|
||||
//関数未実装:error
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NodeType.End:
|
||||
genCode(new EndVM());
|
||||
break;
|
||||
default:
|
||||
stderr.writeln("Compile:NotImpl ", i.type);
|
||||
}
|
||||
@@ -274,6 +298,10 @@ class Compiler
|
||||
{
|
||||
code[i] = new GotoAddr(globalLabel[(cast(GotoS)c).label]);
|
||||
}
|
||||
if(c.type == CodeType.GosubS)
|
||||
{
|
||||
code[i] = new GosubAddr(globalLabel[(cast(GosubS)c).label]);
|
||||
}
|
||||
}
|
||||
return new VM(code, globalIndex + 1, global);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,12 @@ FOR I=0 TO 100
|
||||
ENDIF
|
||||
ENDIF
|
||||
NEXT
|
||||
?NOT 1,!!\"a\"
|
||||
?@HELLOWORLD
|
||||
GOSUB @A
|
||||
END
|
||||
@A
|
||||
?\"SUBROUTINE TEST\"
|
||||
RETURN
|
||||
");
|
||||
version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring);
|
||||
auto vm = parser.compile();
|
||||
|
||||
@@ -23,6 +23,9 @@ enum NodeType
|
||||
Goto,
|
||||
If,
|
||||
For,
|
||||
Gosub,
|
||||
Return,
|
||||
End,
|
||||
}
|
||||
abstract class Node
|
||||
{
|
||||
@@ -245,3 +248,29 @@ class For : Statement
|
||||
this.statements = statements;
|
||||
}
|
||||
}
|
||||
class Gosub : Statement
|
||||
{
|
||||
wstring label;
|
||||
this(wstring name)
|
||||
{
|
||||
this.type = NodeType.Gosub;
|
||||
this.label = name;
|
||||
}
|
||||
}
|
||||
class Return : Statement
|
||||
{
|
||||
Expression expression;
|
||||
this(Expression expression)
|
||||
{
|
||||
this.type = NodeType.Return;
|
||||
this.expression = expression;
|
||||
}
|
||||
}
|
||||
class End : Statement
|
||||
{
|
||||
this()
|
||||
{
|
||||
this.type = NodeType.End;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,9 @@ class Lexical
|
||||
reserved["FOR"] = TokenType.For;
|
||||
reserved["NEXT"] = TokenType.Next;
|
||||
reserved["MOD"] = TokenType.Mod;
|
||||
reserved["GOSUB"] = TokenType.Gosub;
|
||||
reserved["RETURN"] = TokenType.Return;
|
||||
reserved["END"] = TokenType.End;
|
||||
reserved.rehash();
|
||||
line = 1;
|
||||
}
|
||||
@@ -472,7 +475,24 @@ class Parser
|
||||
case TokenType.Goto:
|
||||
lex.popFront();
|
||||
token = lex.front();
|
||||
node = new Goto(token.value.stringValue);
|
||||
if(token.type == TokenType.Label)
|
||||
node = new Goto(token.value.stringValue);
|
||||
else
|
||||
{
|
||||
writeln("NotImpl");
|
||||
syntaxError();
|
||||
}
|
||||
break;
|
||||
case TokenType.Gosub:
|
||||
lex.popFront();
|
||||
token = lex.front();
|
||||
if(token.type == TokenType.Label)
|
||||
node = new Gosub(token.value.stringValue);
|
||||
else
|
||||
{
|
||||
writeln("NotImpl");
|
||||
syntaxError();
|
||||
}
|
||||
break;
|
||||
case TokenType.If:
|
||||
node = if_();
|
||||
@@ -480,6 +500,13 @@ class Parser
|
||||
case TokenType.For:
|
||||
node = forStatement();
|
||||
break;
|
||||
case TokenType.Return:
|
||||
lex.popFront();
|
||||
node = new Return(expression());
|
||||
return node;
|
||||
case TokenType.End:
|
||||
node = new End();
|
||||
break;
|
||||
default:
|
||||
syntaxError();
|
||||
break;
|
||||
@@ -741,7 +768,7 @@ class Parser
|
||||
break;
|
||||
case TokenType.Label://3.1
|
||||
//文字列リテラル
|
||||
|
||||
node = new Constant(token.value);
|
||||
break;
|
||||
case TokenType.Minus:
|
||||
//TODO:UnaryOperatorの実装
|
||||
|
||||
@@ -44,6 +44,9 @@ enum TokenType
|
||||
LogicalAnd,//&&
|
||||
LogicalOr,//||
|
||||
IntDiv,//DIV
|
||||
Gosub,
|
||||
Return,
|
||||
End,
|
||||
}
|
||||
|
||||
struct Token
|
||||
|
||||
Reference in New Issue
Block a user