IFの構文解析
This commit is contained in:
@@ -51,6 +51,8 @@ enum CodeType
|
|||||||
Print,
|
Print,
|
||||||
PopG,
|
PopG,
|
||||||
GotoS,
|
GotoS,
|
||||||
|
GotoFalse,
|
||||||
|
GotoTrue,
|
||||||
}
|
}
|
||||||
abstract class Code
|
abstract class Code
|
||||||
{
|
{
|
||||||
@@ -194,6 +196,38 @@ class GotoS : Code
|
|||||||
stderr.writeln("can't execute");
|
stderr.writeln("can't execute");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class GotoTrue : Code
|
||||||
|
{
|
||||||
|
int address;
|
||||||
|
this(int addr)
|
||||||
|
{
|
||||||
|
this.type = CodeType.GotoTrue;
|
||||||
|
address = addr;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
Value cond;
|
||||||
|
vm.pop(cond);
|
||||||
|
if(cond.boolValue)
|
||||||
|
vm.pc = address - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class GotoFalse : Code
|
||||||
|
{
|
||||||
|
int address;
|
||||||
|
this(int addr)
|
||||||
|
{
|
||||||
|
this.type = CodeType.GotoFalse;
|
||||||
|
address = addr;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
Value cond;
|
||||||
|
vm.pop(cond);
|
||||||
|
if(!cond.boolValue)
|
||||||
|
vm.pc = address - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
class Gosub : Code
|
class Gosub : Code
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ int main(string[] argv)
|
|||||||
writeln(parser.calc());
|
writeln(parser.calc());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parser = new Parser("@A\nA=1+2+3+4\nPRINT 1+1,2+3;10-5,A:A=A*2:PRINT A:GOTO@A");
|
auto parser = new Parser(
|
||||||
|
"@A\nA=1+2+3+4\nPRINT 1+1,2+3;10-5,A:A=A*2:PRINT A
|
||||||
|
IF 1 THEN PRINT 2
|
||||||
|
IF 3 THEN PRINT 4 ELSE PRINT 5
|
||||||
|
");
|
||||||
auto vm = parser.compile();
|
auto vm = parser.compile();
|
||||||
vm.run();
|
vm.run();
|
||||||
readln();
|
readln();
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ enum NodeType
|
|||||||
Print,
|
Print,
|
||||||
Label,
|
Label,
|
||||||
Goto,
|
Goto,
|
||||||
|
If,
|
||||||
}
|
}
|
||||||
abstract class Node
|
abstract class Node
|
||||||
{
|
{
|
||||||
@@ -191,3 +192,16 @@ class Goto : Statement
|
|||||||
this.label = name;
|
this.label = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class If : Statement
|
||||||
|
{
|
||||||
|
Expression condition;
|
||||||
|
Statements then;
|
||||||
|
Statements else_;
|
||||||
|
this(Expression condition, Statements t, Statements e)
|
||||||
|
{
|
||||||
|
this.type = NodeType.If;
|
||||||
|
this.condition = condition;
|
||||||
|
this.then = t;
|
||||||
|
this.else_ = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ class Lexical
|
|||||||
reserved["NOT"] = TokenType.Not;
|
reserved["NOT"] = TokenType.Not;
|
||||||
reserved["PRINT"] = TokenType.Print;
|
reserved["PRINT"] = TokenType.Print;
|
||||||
reserved["GOTO"] = TokenType.Goto;
|
reserved["GOTO"] = TokenType.Goto;
|
||||||
|
reserved["IF"] = TokenType.If;
|
||||||
|
reserved["THEN"] = TokenType.Then;
|
||||||
|
reserved["ELSE"] = TokenType.Else;
|
||||||
|
reserved["ENDIF"] = TokenType.Endif;
|
||||||
reserved.rehash();
|
reserved.rehash();
|
||||||
line = 1;
|
line = 1;
|
||||||
}
|
}
|
||||||
@@ -289,6 +293,7 @@ class Parser
|
|||||||
}
|
}
|
||||||
Statements parseProgram()
|
Statements parseProgram()
|
||||||
{
|
{
|
||||||
|
lex.popFront();
|
||||||
auto statements = new Statements();
|
auto statements = new Statements();
|
||||||
while(!lex.empty())
|
while(!lex.empty())
|
||||||
{
|
{
|
||||||
@@ -302,19 +307,37 @@ class Parser
|
|||||||
}
|
}
|
||||||
return statements;
|
return statements;
|
||||||
}
|
}
|
||||||
|
Statements ifstatements()
|
||||||
|
{
|
||||||
|
auto statements = new Statements();
|
||||||
|
while(!lex.empty())
|
||||||
|
{
|
||||||
|
auto type = lex.front().type;
|
||||||
|
if(type == TokenType.NewLine) break;
|
||||||
|
if(type == TokenType.Else) break;
|
||||||
|
if(type == TokenType.Endif) break;
|
||||||
|
auto statement = statement();
|
||||||
|
if(statement != Statement.NOP)
|
||||||
|
{
|
||||||
|
statements.addStatement(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return statements;
|
||||||
|
}
|
||||||
void syntaxError()
|
void syntaxError()
|
||||||
{
|
{
|
||||||
stderr.writeln("Syntax error (", lex.getLine(), ')');
|
stderr.writeln("Syntax error (", lex.getLine(), ')', " Mysterious ", lex.front().type);
|
||||||
}
|
}
|
||||||
//statement
|
//statement
|
||||||
Statement statement()
|
Statement statement()
|
||||||
{
|
{
|
||||||
lex.popFront();
|
|
||||||
auto token = lex.front();
|
auto token = lex.front();
|
||||||
|
Statement node = null;
|
||||||
switch(token.type)
|
switch(token.type)
|
||||||
{
|
{
|
||||||
case TokenType.Print:
|
case TokenType.Print:
|
||||||
return print();
|
node = print();
|
||||||
|
return node;
|
||||||
case TokenType.Iden:
|
case TokenType.Iden:
|
||||||
{
|
{
|
||||||
wstring name = token.value.stringValue;
|
wstring name = token.value.stringValue;
|
||||||
@@ -322,7 +345,8 @@ class Parser
|
|||||||
token = lex.front();
|
token = lex.front();
|
||||||
if(token.type == TokenType.Assign)
|
if(token.type == TokenType.Assign)
|
||||||
{
|
{
|
||||||
return assign(name);
|
node = assign(name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
//命令呼び出し
|
//命令呼び出し
|
||||||
}
|
}
|
||||||
@@ -331,16 +355,69 @@ class Parser
|
|||||||
case TokenType.NewLine:
|
case TokenType.NewLine:
|
||||||
break;
|
break;
|
||||||
case TokenType.Label:
|
case TokenType.Label:
|
||||||
return new Label(token.value.stringValue);
|
node = new Label(token.value.stringValue);
|
||||||
|
break;
|
||||||
case TokenType.Goto:
|
case TokenType.Goto:
|
||||||
lex.popFront();
|
lex.popFront();
|
||||||
token = lex.front();
|
token = lex.front();
|
||||||
return new Goto(token.value.stringValue);
|
node = new Goto(token.value.stringValue);
|
||||||
|
break;
|
||||||
|
case TokenType.If:
|
||||||
|
node = if_();
|
||||||
|
return node;
|
||||||
default:
|
default:
|
||||||
syntaxError();
|
syntaxError();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return null;
|
lex.popFront();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
If if_()
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
auto token = lex.front();
|
||||||
|
auto expr = expression();
|
||||||
|
if(expr is null)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
token = lex.front();
|
||||||
|
if(token.type != TokenType.Then)
|
||||||
|
{
|
||||||
|
if(token.type != TokenType.Goto)
|
||||||
|
{
|
||||||
|
//IF expr GOSUBは不可
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(token.type != TokenType.Goto)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
token = lex.front();
|
||||||
|
}
|
||||||
|
if(token.type == TokenType.NewLine)
|
||||||
|
{
|
||||||
|
writeln("NotImpl: Multi line if");
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
auto then = ifstatements();
|
||||||
|
token = lex.front();
|
||||||
|
lex.popFront();
|
||||||
|
Statements else_;
|
||||||
|
if(token.type == TokenType.Else)
|
||||||
|
{
|
||||||
|
if(lex.front().type == TokenType.NewLine)
|
||||||
|
{
|
||||||
|
//3.1現在だとエラー
|
||||||
|
syntaxError();
|
||||||
|
}
|
||||||
|
else_ = ifstatements();
|
||||||
|
}
|
||||||
|
auto if_ = new If(expr, then, else_);
|
||||||
|
return if_;
|
||||||
}
|
}
|
||||||
Assign assign(wstring name)
|
Assign assign(wstring name)
|
||||||
{
|
{
|
||||||
@@ -379,13 +456,16 @@ class Parser
|
|||||||
print.addLine();
|
print.addLine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(token.type != TokenType.Colon && token.type != TokenType.NewLine && token.type != TokenType.Semicolon && token.type != TokenType.Comma)
|
if(token.type != TokenType.Colon && token.type != TokenType.NewLine &&
|
||||||
|
token.type != TokenType.Semicolon && token.type != TokenType.Comma &&
|
||||||
|
token.type != TokenType.Else && token.type != TokenType.Endif)
|
||||||
{
|
{
|
||||||
syntaxError();
|
syntaxError();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(token.type == TokenType.Colon || token.type == TokenType.NewLine)
|
if(token.type == TokenType.Colon || token.type == TokenType.NewLine ||
|
||||||
|
token.type == TokenType.Else || token.type == TokenType.Endif)
|
||||||
{
|
{
|
||||||
print.addLine();
|
print.addLine();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ enum TokenType
|
|||||||
Assign,
|
Assign,
|
||||||
Label,
|
Label,
|
||||||
Goto,
|
Goto,
|
||||||
|
Then,
|
||||||
|
Else,
|
||||||
|
Endif,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
|
|||||||
@@ -45,4 +45,19 @@ struct Value
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool boolValue()
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case ValueType.Double:
|
||||||
|
return this.doubleValue != 0;
|
||||||
|
case ValueType.Integer:
|
||||||
|
return this.integerValue != 0;
|
||||||
|
case ValueType.String:
|
||||||
|
return true;//3.1現在では文字列はtrue(ただし!"A"などは動かない)
|
||||||
|
default:
|
||||||
|
//配列はtype missmatch
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user