コンパイルして実行できるようにした
This commit is contained in:
@@ -1,32 +1,112 @@
|
||||
module otya.smilebasic.vm;
|
||||
import otya.smilebasic.type;
|
||||
import otya.smilebasic.token;
|
||||
import std.uni;
|
||||
import std.conv;
|
||||
import std.stdio;
|
||||
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
|
||||
{
|
||||
PushI,
|
||||
PushD,
|
||||
PushS,
|
||||
Push,
|
||||
Operate,
|
||||
Return,
|
||||
Goto,
|
||||
Gosub,
|
||||
Print,
|
||||
}
|
||||
abstract class Code
|
||||
{
|
||||
CodeType type;
|
||||
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
|
||||
*/
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module otya.smilebasic.compiler;
|
||||
import otya.smilebasic.node;
|
||||
import otya.smilebasic.token;
|
||||
import otya.smilebasic.vm;
|
||||
import otya.smilebasic.type;
|
||||
import std.stdio;
|
||||
class Compiler
|
||||
{
|
||||
@@ -8,18 +10,85 @@ class Compiler
|
||||
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)
|
||||
{
|
||||
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:
|
||||
stderr.writeln("Compile:NotImpl ", i.type);
|
||||
}
|
||||
}
|
||||
return new VM(code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ import std.stdio;
|
||||
import otya.smilebasic.parser;
|
||||
int main(string[] argv)
|
||||
{
|
||||
writeln("Hello D-World!");
|
||||
version(none)
|
||||
{
|
||||
auto parser = new Parser("ADD(ADD(1,2,3,4,5,6),2,3,4,5,6)");
|
||||
writeln(parser.calc());
|
||||
}
|
||||
|
||||
auto parser = new Parser("PRINT 1+1");
|
||||
parser.compile();
|
||||
auto parser = new Parser("PRINT 1+1,2+3;10-5");
|
||||
auto vm = parser.compile();
|
||||
vm.run();
|
||||
readln();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -260,10 +260,10 @@ class Parser
|
||||
return - - -1;
|
||||
}
|
||||
}
|
||||
void compile()
|
||||
auto compile()
|
||||
{
|
||||
auto compiler = new Compiler(parseProgram());
|
||||
compiler.compile();
|
||||
return compiler.compile();
|
||||
}
|
||||
Statements parseProgram()
|
||||
{
|
||||
@@ -305,17 +305,6 @@ class Parser
|
||||
print.addLine();
|
||||
break;
|
||||
}
|
||||
if(token.type == TokenType.Semicolon)
|
||||
{
|
||||
addline = false;
|
||||
continue;
|
||||
}
|
||||
if(token.type == TokenType.Comma)
|
||||
{
|
||||
print.addTab();
|
||||
addline = false;
|
||||
continue;
|
||||
}
|
||||
addline = true;
|
||||
auto exp = expression();
|
||||
if(exp is null)
|
||||
@@ -324,13 +313,28 @@ class Parser
|
||||
continue;
|
||||
}
|
||||
print.addArgument(exp);
|
||||
lex.popFront();
|
||||
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)
|
||||
{
|
||||
addline = false;
|
||||
continue;
|
||||
}
|
||||
if(token.type == TokenType.Comma)
|
||||
{
|
||||
print.addTab();
|
||||
addline = false;
|
||||
continue;
|
||||
}
|
||||
token = lex.front();
|
||||
}
|
||||
}
|
||||
return print;
|
||||
}
|
||||
|
||||
@@ -34,4 +34,15 @@ struct Value
|
||||
this.type = ValueType.String;
|
||||
stringValue = value;
|
||||
}
|
||||
void castOp(ValueType type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ValueType.Double:
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user