1
0

IFの構文解析

This commit is contained in:
otya128
2015-06-06 17:11:02 +09:00
parent 2eaab2ef55
commit 5cab924046
6 changed files with 160 additions and 10 deletions

View File

@@ -51,6 +51,8 @@ enum CodeType
Print,
PopG,
GotoS,
GotoFalse,
GotoTrue,
}
abstract class Code
{
@@ -194,6 +196,38 @@ class GotoS : Code
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
{

View File

@@ -8,7 +8,11 @@ int main(string[] argv)
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();
vm.run();
readln();

View File

@@ -20,6 +20,7 @@ enum NodeType
Print,
Label,
Goto,
If,
}
abstract class Node
{
@@ -191,3 +192,16 @@ class Goto : Statement
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;
}
}

View File

@@ -39,6 +39,10 @@ class Lexical
reserved["NOT"] = TokenType.Not;
reserved["PRINT"] = TokenType.Print;
reserved["GOTO"] = TokenType.Goto;
reserved["IF"] = TokenType.If;
reserved["THEN"] = TokenType.Then;
reserved["ELSE"] = TokenType.Else;
reserved["ENDIF"] = TokenType.Endif;
reserved.rehash();
line = 1;
}
@@ -289,6 +293,7 @@ class Parser
}
Statements parseProgram()
{
lex.popFront();
auto statements = new Statements();
while(!lex.empty())
{
@@ -302,19 +307,37 @@ class Parser
}
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()
{
stderr.writeln("Syntax error (", lex.getLine(), ')');
stderr.writeln("Syntax error (", lex.getLine(), ')', " Mysterious ", lex.front().type);
}
//statement
Statement statement()
{
lex.popFront();
auto token = lex.front();
Statement node = null;
switch(token.type)
{
case TokenType.Print:
return print();
node = print();
return node;
case TokenType.Iden:
{
wstring name = token.value.stringValue;
@@ -322,7 +345,8 @@ class Parser
token = lex.front();
if(token.type == TokenType.Assign)
{
return assign(name);
node = assign(name);
break;
}
//命令呼び出し
}
@@ -331,16 +355,69 @@ class Parser
case TokenType.NewLine:
break;
case TokenType.Label:
return new Label(token.value.stringValue);
node = new Label(token.value.stringValue);
break;
case TokenType.Goto:
lex.popFront();
token = lex.front();
return new Goto(token.value.stringValue);
node = new Goto(token.value.stringValue);
break;
case TokenType.If:
node = if_();
return node;
default:
syntaxError();
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)
{
@@ -379,13 +456,16 @@ class Parser
print.addLine();
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();
}
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();
break;

View File

@@ -27,6 +27,9 @@ enum TokenType
Assign,
Label,
Goto,
Then,
Else,
Endif,
}
struct Token

View File

@@ -45,4 +45,19 @@ struct Value
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;
}
}
}