break,continue実装,var,dim実装中
This commit is contained in:
@@ -5,6 +5,19 @@ import otya.smilebasic.vm;
|
||||
import otya.smilebasic.type;
|
||||
import otya.smilebasic.error;
|
||||
import std.stdio;
|
||||
class Scope
|
||||
{
|
||||
GotoAddr breakAddr;
|
||||
GotoAddr continueAddr;
|
||||
this()
|
||||
{
|
||||
}
|
||||
this(GotoAddr breakAddr, GotoAddr continueAddr)
|
||||
{
|
||||
this.breakAddr = breakAddr;
|
||||
this.continueAddr = continueAddr;
|
||||
}
|
||||
}
|
||||
class Compiler
|
||||
{
|
||||
Statements statements;
|
||||
@@ -139,19 +152,19 @@ class Compiler
|
||||
break;
|
||||
}
|
||||
}
|
||||
void compileIf(If node)
|
||||
void compileIf(If node, Scope sc)
|
||||
{
|
||||
compileExpression(node.condition);
|
||||
//条件式がfalseならendif or elseに飛ぶ
|
||||
auto else_ = genCodeGotoFalse();
|
||||
compileStatements(node.then);
|
||||
compileStatements(node.then, sc);
|
||||
//もしelseもあるのならば、endifに飛ぶ
|
||||
GotoAddr then;
|
||||
if(node.hasElse)
|
||||
{
|
||||
then = genCodeGoto();
|
||||
else_.address = code.length;
|
||||
compileStatements(node.else_);
|
||||
compileStatements(node.else_, sc);
|
||||
then.address = code.length;
|
||||
}
|
||||
else
|
||||
@@ -160,9 +173,9 @@ class Compiler
|
||||
else_.address = code.length;
|
||||
}
|
||||
}
|
||||
void compileFor(For node)
|
||||
void compileFor(For node, Scope s)
|
||||
{
|
||||
compileStatement(node.initExpression);
|
||||
compileStatement(node.initExpression, s);
|
||||
auto forstart = code.length;
|
||||
compileExpression(node.stepExpression);
|
||||
genCodeImm(Value(0));
|
||||
@@ -194,7 +207,9 @@ class Compiler
|
||||
genCodeOP(TokenType.Less);
|
||||
genCode(breakAddr);
|
||||
forAddr.address = code.length;
|
||||
compileStatements(node.statements);
|
||||
s = new Scope(new GotoAddr(-1), new GotoAddr(-1));
|
||||
compileStatements(node.statements, s);
|
||||
s.continueAddr.address = code.length;
|
||||
//counterに加算する
|
||||
genCodePushGlobal(getGlobalVarIndex(node.initExpression.name));
|
||||
compileExpression(node.stepExpression);
|
||||
@@ -202,16 +217,17 @@ class Compiler
|
||||
genCodePopGlobal(getGlobalVarIndex(node.initExpression.name));
|
||||
genCodeGoto(forstart);
|
||||
breakAddr.address = code.length;
|
||||
s.breakAddr.address = code.length;
|
||||
}
|
||||
|
||||
void compileStatements(Statements statements)
|
||||
void compileStatements(Statements statements, Scope sc)
|
||||
{
|
||||
foreach(Statement s ; statements.statements)
|
||||
{
|
||||
compileStatement(s);
|
||||
compileStatement(s, sc);
|
||||
}
|
||||
}
|
||||
void compileStatement(Statement i)
|
||||
void compileStatement(Statement i, Scope s)
|
||||
{
|
||||
switch(i.type)
|
||||
{
|
||||
@@ -257,10 +273,10 @@ class Compiler
|
||||
}
|
||||
break;
|
||||
case NodeType.If:
|
||||
compileIf(cast(If)i);
|
||||
compileIf(cast(If)i, s);
|
||||
break;
|
||||
case NodeType.For:
|
||||
compileFor(cast(For)i);
|
||||
compileFor(cast(For)i, s);
|
||||
break;
|
||||
case NodeType.Gosub:
|
||||
{
|
||||
@@ -282,15 +298,32 @@ class Compiler
|
||||
case NodeType.End:
|
||||
genCode(new EndVM());
|
||||
break;
|
||||
case NodeType.Break:
|
||||
if(s.breakAddr is null)
|
||||
{
|
||||
//syntax-error
|
||||
break;
|
||||
}
|
||||
genCode(s.breakAddr);
|
||||
break;
|
||||
case NodeType.Continue:
|
||||
if(s.continueAddr is null)
|
||||
{
|
||||
//syntax-error
|
||||
break;
|
||||
}
|
||||
genCode(s.continueAddr);
|
||||
break;
|
||||
default:
|
||||
stderr.writeln("Compile:NotImpl ", i.type);
|
||||
}
|
||||
}
|
||||
VM compile()
|
||||
{
|
||||
Scope s = new Scope();
|
||||
foreach(Statement i ; statements.statements)
|
||||
{
|
||||
compileStatement(i);
|
||||
compileStatement(i, s);
|
||||
}
|
||||
foreach(int i, Code c; code)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,11 @@ NEXT
|
||||
?(1 OR 2 XOR 3)
|
||||
?(1 OR 2 XOR 3 OR 4)
|
||||
?@HELLOWORLD
|
||||
FOR I=0 TO 10
|
||||
IF I==4 THEN BREAK
|
||||
IF I==1 THEN CONTINUE
|
||||
?I
|
||||
NEXT
|
||||
GOSUB @A
|
||||
END
|
||||
@A
|
||||
|
||||
@@ -26,6 +26,10 @@ enum NodeType
|
||||
Gosub,
|
||||
Return,
|
||||
End,
|
||||
Break,
|
||||
Continue,
|
||||
DefineVariable,
|
||||
DefineArray,
|
||||
}
|
||||
abstract class Node
|
||||
{
|
||||
@@ -273,4 +277,39 @@ class End : Statement
|
||||
this.type = NodeType.End;
|
||||
}
|
||||
}
|
||||
|
||||
class Break : Statement
|
||||
{
|
||||
this()
|
||||
{
|
||||
this.type = NodeType.Break;
|
||||
}
|
||||
}
|
||||
class Continue : Statement
|
||||
{
|
||||
this()
|
||||
{
|
||||
this.type = NodeType.Continue;
|
||||
}
|
||||
}
|
||||
class DefineVariable : Statement
|
||||
{
|
||||
wstring name;
|
||||
Expression expression;
|
||||
this(wstring name, Expression expr)
|
||||
{
|
||||
this.type = NodeType.DefineVariable;
|
||||
this.name = name;
|
||||
this.expression = expr;
|
||||
}
|
||||
}
|
||||
class DefineArray : Statement
|
||||
{
|
||||
wstring name;
|
||||
int[] dim;
|
||||
this(wstring name, int[] dim)
|
||||
{
|
||||
this.type = NodeType.DefineArray;
|
||||
this.name = name;
|
||||
this.dim = dim;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ class Lexical
|
||||
reserved["GOSUB"] = TokenType.Gosub;
|
||||
reserved["RETURN"] = TokenType.Return;
|
||||
reserved["END"] = TokenType.End;
|
||||
reserved["BREAK"] = TokenType.Break;
|
||||
reserved["CONTINUE"] = TokenType.Continue;
|
||||
reserved["VAR"] = TokenType.Var;
|
||||
reserved["DIM"] = TokenType.Var;
|
||||
reserved.rehash();
|
||||
line = 1;
|
||||
}
|
||||
@@ -521,6 +525,16 @@ class Parser
|
||||
case TokenType.End:
|
||||
node = new End();
|
||||
break;
|
||||
case TokenType.Break:
|
||||
node = new Break();
|
||||
break;
|
||||
case TokenType.Continue:
|
||||
node = new Continue();
|
||||
break;
|
||||
case TokenType.Var:
|
||||
lex.popFront();
|
||||
node = var();
|
||||
break;
|
||||
default:
|
||||
syntaxError();
|
||||
break;
|
||||
@@ -528,6 +542,34 @@ class Parser
|
||||
lex.popFront();
|
||||
return node;
|
||||
}
|
||||
Statement var()
|
||||
{
|
||||
Token token = lex.front();
|
||||
if(token.type != TokenType.Iden)
|
||||
{
|
||||
//TODO:VAR("A")の実装
|
||||
syntaxError();
|
||||
return null;
|
||||
}
|
||||
wstring name = token.value.stringValue;
|
||||
lex.popFront();
|
||||
token = lex.front();
|
||||
Expression expr;
|
||||
//VAR iden=expr
|
||||
if(token.type == TokenType.Equal)
|
||||
{
|
||||
lex.popFront();
|
||||
expr = expression();
|
||||
}
|
||||
DefineVariable node = new DefineVariable(name, expr);
|
||||
//VARの評価順は順番通り
|
||||
//VAR iden[=expr],
|
||||
if(token.type == TokenType.Comma)
|
||||
{
|
||||
lex.popFront();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
For forStatement()
|
||||
{
|
||||
For node;
|
||||
|
||||
@@ -47,6 +47,9 @@ enum TokenType
|
||||
Gosub,
|
||||
Return,
|
||||
End,
|
||||
Break,
|
||||
Continue,
|
||||
Var,
|
||||
}
|
||||
|
||||
struct Token
|
||||
|
||||
@@ -18,7 +18,7 @@ struct Value
|
||||
int integerValue;
|
||||
double doubleValue;
|
||||
wstring stringValue;
|
||||
int[] intArray;
|
||||
Array!int intArray;
|
||||
}
|
||||
this(int value)
|
||||
{
|
||||
@@ -70,3 +70,47 @@ struct Value
|
||||
}
|
||||
}
|
||||
}
|
||||
class Array(T)
|
||||
{
|
||||
T[] array;
|
||||
//最大要素数2^^31
|
||||
//4次元配列
|
||||
int[4] dim;
|
||||
int dimCount;
|
||||
this(int len)
|
||||
{
|
||||
dim[0] = len;
|
||||
dim[1] = 0;
|
||||
dim[2] = 0;
|
||||
dim[3] = 0;
|
||||
array = new T[len];
|
||||
dimCount = 1;
|
||||
}
|
||||
this(int[] dim)
|
||||
{
|
||||
int len = 1;
|
||||
foreach(int i; dim)
|
||||
{
|
||||
len *= i;
|
||||
}
|
||||
array = new T[len];
|
||||
dimCount = dim.length;
|
||||
}
|
||||
T opIndex(int i1)
|
||||
{
|
||||
return array[i1];
|
||||
}
|
||||
T opIndex(int i1, int i2)
|
||||
{
|
||||
return array[i1 * dim[0] + i2];
|
||||
}
|
||||
T opIndex(int i1, int i2, int i3)
|
||||
{
|
||||
return array[i1 * dim[0] * dim[1] + i2 * dim[1] + i3];
|
||||
}
|
||||
T opIndex(int i1, int i2, int i3, int i4)
|
||||
{
|
||||
return array[i1];//array[i1 * dim[0] * dim[1] * dim[2] + i2 * dim[1] + i3];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user