コンパイルして実行できるようにした
This commit is contained in:
@@ -1,32 +1,112 @@
|
|||||||
module otya.smilebasic.vm;
|
module otya.smilebasic.vm;
|
||||||
|
import otya.smilebasic.type;
|
||||||
|
import otya.smilebasic.token;
|
||||||
|
import std.uni;
|
||||||
|
import std.conv;
|
||||||
|
import std.stdio;
|
||||||
class VM
|
class VM
|
||||||
{
|
{
|
||||||
|
Code[] code;
|
||||||
|
int stacki;
|
||||||
|
Value[] stack;
|
||||||
|
this(Code[] code)
|
||||||
|
{
|
||||||
|
this.code = code;
|
||||||
|
this.stack = new Value[1024 * 1024];
|
||||||
|
}
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < this.code.length; i++)
|
||||||
|
{
|
||||||
|
code[i].execute(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void push(ref Value value)
|
||||||
|
{
|
||||||
|
stack[stacki++] = value;
|
||||||
|
}
|
||||||
|
void pop(out Value value)
|
||||||
|
{
|
||||||
|
value = stack[--stacki];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
enum CodeType
|
enum CodeType
|
||||||
{
|
{
|
||||||
PushI,
|
Push,
|
||||||
PushD,
|
|
||||||
PushS,
|
|
||||||
Operate,
|
Operate,
|
||||||
Return,
|
Return,
|
||||||
Goto,
|
Goto,
|
||||||
Gosub,
|
Gosub,
|
||||||
|
Print,
|
||||||
}
|
}
|
||||||
abstract class Code
|
abstract class Code
|
||||||
{
|
{
|
||||||
CodeType type;
|
CodeType type;
|
||||||
abstract void execute(VM vm);
|
abstract void execute(VM vm);
|
||||||
}
|
}
|
||||||
|
class PrintCode : Code
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
this(int count)
|
||||||
|
{
|
||||||
|
this.type = CodeType.Print;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
for(int i = 0;i < count; i++)
|
||||||
|
{
|
||||||
|
Value arg;
|
||||||
|
vm.pop(arg);
|
||||||
|
switch(arg.type)
|
||||||
|
{
|
||||||
|
case ValueType.Integer:
|
||||||
|
write(arg.integerValue);
|
||||||
|
break;
|
||||||
|
case ValueType.String:
|
||||||
|
write(cast(string)arg.stringValue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//type missmatch
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* スタックにPush
|
* スタックにPush
|
||||||
*/
|
*/
|
||||||
class Push : Code
|
class Push : Code
|
||||||
{
|
{
|
||||||
|
Value imm;
|
||||||
|
this(Value imm)
|
||||||
|
{
|
||||||
|
this.type = CodeType.Push;
|
||||||
|
this.imm = imm;
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
vm.push(imm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class Operate : Code
|
class Operate : Code
|
||||||
{
|
{
|
||||||
|
TokenType operator;
|
||||||
|
this(TokenType op)
|
||||||
|
{
|
||||||
|
this.operator = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
Value l;
|
||||||
|
Value r;
|
||||||
|
vm.pop(l);
|
||||||
|
vm.pop(r);
|
||||||
|
//とりあえずInteger
|
||||||
|
l.integerValue += r.integerValue;
|
||||||
|
vm.push(l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class Goto : Code
|
class Goto : Code
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
module otya.smilebasic.compiler;
|
module otya.smilebasic.compiler;
|
||||||
import otya.smilebasic.node;
|
import otya.smilebasic.node;
|
||||||
|
import otya.smilebasic.token;
|
||||||
import otya.smilebasic.vm;
|
import otya.smilebasic.vm;
|
||||||
|
import otya.smilebasic.type;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
@@ -8,18 +10,85 @@ class Compiler
|
|||||||
this(Statements statements)
|
this(Statements statements)
|
||||||
{
|
{
|
||||||
this.statements = statements;
|
this.statements = statements;
|
||||||
|
code = new Code[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile()
|
Code[] code;
|
||||||
|
void genCodeImm(Value value)
|
||||||
|
{
|
||||||
|
code ~= new Push(value);
|
||||||
|
}
|
||||||
|
void genCodeOP(TokenType op)
|
||||||
|
{
|
||||||
|
code ~= new Operate(op);
|
||||||
|
}
|
||||||
|
void compileExpression(Expression exp)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch(exp.type)
|
||||||
|
{
|
||||||
|
case NodeType.Constant:
|
||||||
|
genCodeImm((cast(Constant)exp).value);
|
||||||
|
break;
|
||||||
|
case NodeType.BinaryOperator:
|
||||||
|
{
|
||||||
|
auto binop = cast(BinaryOperator)exp;
|
||||||
|
compileExpression(binop.item1);
|
||||||
|
compileExpression(binop.item2);
|
||||||
|
genCodeOP(binop.operator);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NodeType.Variable:
|
||||||
|
break;
|
||||||
|
case NodeType.CallFunction:
|
||||||
|
{
|
||||||
|
auto func = cast(CallFunction)exp;
|
||||||
|
if(func.name == "ADD")
|
||||||
|
{
|
||||||
|
foreach_reverse(Expression i ; func.args)
|
||||||
|
{
|
||||||
|
compileExpression(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VM compile()
|
||||||
{
|
{
|
||||||
Code[] code = new Code[0];
|
|
||||||
foreach(Statement i ; statements.statements)
|
foreach(Statement i ; statements.statements)
|
||||||
{
|
{
|
||||||
switch(i.type)
|
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;
|
||||||
default:
|
default:
|
||||||
stderr.writeln("Compile:NotImpl ", i.type);
|
stderr.writeln("Compile:NotImpl ", i.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return new VM(code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import std.stdio;
|
|||||||
import otya.smilebasic.parser;
|
import otya.smilebasic.parser;
|
||||||
int main(string[] argv)
|
int main(string[] argv)
|
||||||
{
|
{
|
||||||
writeln("Hello D-World!");
|
|
||||||
version(none)
|
version(none)
|
||||||
{
|
{
|
||||||
auto parser = new Parser("ADD(ADD(1,2,3,4,5,6),2,3,4,5,6)");
|
auto parser = new Parser("ADD(ADD(1,2,3,4,5,6),2,3,4,5,6)");
|
||||||
writeln(parser.calc());
|
writeln(parser.calc());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parser = new Parser("PRINT 1+1");
|
auto parser = new Parser("PRINT 1+1,2+3;10-5");
|
||||||
parser.compile();
|
auto vm = parser.compile();
|
||||||
|
vm.run();
|
||||||
readln();
|
readln();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,10 +260,10 @@ class Parser
|
|||||||
return - - -1;
|
return - - -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void compile()
|
auto compile()
|
||||||
{
|
{
|
||||||
auto compiler = new Compiler(parseProgram());
|
auto compiler = new Compiler(parseProgram());
|
||||||
compiler.compile();
|
return compiler.compile();
|
||||||
}
|
}
|
||||||
Statements parseProgram()
|
Statements parseProgram()
|
||||||
{
|
{
|
||||||
@@ -305,6 +305,23 @@ class Parser
|
|||||||
print.addLine();
|
print.addLine();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
addline = true;
|
||||||
|
auto exp = expression();
|
||||||
|
if(exp is null)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
print.addArgument(exp);
|
||||||
|
token = lex.front();
|
||||||
|
if(lex.empty()) break;
|
||||||
|
if(token.type != TokenType.Colon && token.type != TokenType.NewLine && token.type != TokenType.Semicolon && token.type != TokenType.Comma)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
if(token.type == TokenType.Semicolon)
|
if(token.type == TokenType.Semicolon)
|
||||||
{
|
{
|
||||||
addline = false;
|
addline = false;
|
||||||
@@ -316,20 +333,7 @@ class Parser
|
|||||||
addline = false;
|
addline = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addline = true;
|
|
||||||
auto exp = expression();
|
|
||||||
if(exp is null)
|
|
||||||
{
|
|
||||||
syntaxError();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
print.addArgument(exp);
|
|
||||||
lex.popFront();
|
|
||||||
token = lex.front();
|
token = lex.front();
|
||||||
if(lex.empty()) break;
|
|
||||||
if(token.type != TokenType.Colon && token.type != TokenType.NewLine && token.type != TokenType.Semicolon && token.type != TokenType.Comma)
|
|
||||||
{
|
|
||||||
syntaxError();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return print;
|
return print;
|
||||||
|
|||||||
@@ -34,4 +34,15 @@ struct Value
|
|||||||
this.type = ValueType.String;
|
this.type = ValueType.String;
|
||||||
stringValue = value;
|
stringValue = value;
|
||||||
}
|
}
|
||||||
|
void castOp(ValueType type)
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case ValueType.Double:
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user