diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index 9d44aa0..8c41dc9 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -37,6 +37,24 @@ class Compiler { code ~= new GotoS(label); } + GotoAddr genCodeGoto() + { + auto c = new GotoAddr(-1); + code ~= c; + return c; + } + GotoTrue genCodeGotoTrue() + { + auto c = new GotoTrue(-1); + code ~= c; + return c; + } + GotoFalse genCodeGotoFalse() + { + auto c = new GotoFalse(-1); + code ~= c; + return c; + } int defineGlobalVarIndex(wstring name) { int global = this.global.get(name, 0); @@ -98,56 +116,92 @@ class Compiler break; } } + void compileIf(If node) + { + compileExpression(node.condition); + //条件式がfalseならendif or elseに飛ぶ + auto else_ = genCodeGotoFalse(); + compileStatements(node.then); + //もしelseもあるのならば、endifに飛ぶ + GotoAddr then; + if(node.hasElse) + { + then = genCodeGoto(); + else_.address = code.length; + compileStatements(node.else_); + then.address = code.length; + } + else + { + //endifに飛ばす + else_.address = code.length; + } + } + + void compileStatements(Statements statements) + { + foreach(Statement s ; statements.statements) + { + compileStatement(s); + } + } + void compileStatement(Statement i) + { + switch(i.type) + { + case NodeType.Print: + { + auto print = cast(Print)i; + foreach_reverse(PrintArgument j ; print.args) + { + switch(j.type) + { + case PrintArgumentType.Expression: + compileExpression(j.expression); + break; + case PrintArgumentType.Line: + genCodeImm(Value("\n")); + break; + case PrintArgumentType.Tab: + genCodeImm(Value("\t")); + break; + default: + break; + } + } + code ~= new PrintCode(print.args.length); + } + break; + case NodeType.Assign: + { + auto assign = cast(Assign)i; + compileExpression(assign.expression); + genCodePopGlobal(getGlobalVarIndex(assign.name)); + } + break; + case NodeType.Label: + { + auto label = cast(Label)i; + globalLabel[label.label] = code.length; + } + break; + case NodeType.Goto: + { + genCodeGoto((cast(Goto)i).label); + } + break; + case NodeType.If: + compileIf(cast(If)i); + break; + default: + stderr.writeln("Compile:NotImpl ", i.type); + } + } VM compile() { foreach(Statement i ; statements.statements) { - switch(i.type) - { - case NodeType.Print: - { - auto print = cast(Print)i; - foreach_reverse(PrintArgument j ; print.args) - { - switch(j.type) - { - case PrintArgumentType.Expression: - compileExpression(j.expression); - break; - case PrintArgumentType.Line: - genCodeImm(Value("\n")); - break; - case PrintArgumentType.Tab: - genCodeImm(Value("\t")); - break; - default: - break; - } - } - code ~= new PrintCode(print.args.length); - } - break; - case NodeType.Assign: - { - auto assign = cast(Assign)i; - compileExpression(assign.expression); - genCodePopGlobal(getGlobalVarIndex(assign.name)); - } - break; - case NodeType.Label: - { - auto label = cast(Label)i; - globalLabel[label.label] = code.length; - } - break; - case NodeType.Goto: - { - genCodeGoto((cast(Goto)i).label); - } - break; - default: - stderr.writeln("Compile:NotImpl ", i.type); - } + compileStatement(i); } foreach(int i, Code c; code) { diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 719fd7b..dae90cb 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -11,7 +11,7 @@ int main(string[] argv) 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 +IF 0 THEN PRINT 4 ELSE PRINT 5 "); auto vm = parser.compile(); vm.run(); diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 96c5d57..9ad45b7 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -204,4 +204,8 @@ class If : Statement this.then = t; this.else_ = e; } + bool hasElse() + { + return !(else_ is null) && else_.statements.length != 0; + } }