diff --git a/SMILEBASIC/VM.d b/SMILEBASIC/VM.d index f53f9e2..aae32e7 100644 --- a/SMILEBASIC/VM.d +++ b/SMILEBASIC/VM.d @@ -119,6 +119,9 @@ class PrintCode : Code case ValueType.Integer: write(arg.integerValue); break; + case ValueType.Double: + write(arg.doubleValue); + break; case ValueType.String: write(arg.stringValue); break; @@ -235,6 +238,16 @@ class Operate : Code break; } vm.pop(l); + if(l.type == ValueType.IntegerArray) + //l.type == ValueType.StringArray || l.type == ValueType.DoubleArray) + { + if(operator != TokenType.LBracket) + { + throw new TypeMismatch(); + } + vm.push(Value(l.integerArray[ri])); + return; + } if(l.type == ValueType.String) { wstring ls = l.stringValue; @@ -291,6 +304,9 @@ class Operate : Code case TokenType.GreaterEqual: vm.push(Value(3)); return; + case TokenType.LBracket: + vm.push(Value(ls[ri].to!wstring)); + return; default: //type mismatch throw new TypeMismatch(); @@ -491,5 +507,47 @@ class EndVM : Code { vm.end(); } -} - +} +class NewArray : Code +{ + ValueType type; + int index; + int size; + int[] dim; + this(ValueType type, int size, int index) + { + dim = new int[size]; + this.size = size; + this.type = type; + this.index = index; + } + override void execute(VM vm) + { + for(int i = size - 1; i >= 0; i--) + { + Value v; + vm.pop(v); + if(v.type == ValueType.Double) + { + dim[i] = cast(int)v.doubleValue; + continue; + } + if(v.type == ValueType.Integer) + { + dim[i] = v.integerValue; + continue; + } + throw new TypeMismatch(); + } + switch(type) + { + case ValueType.Integer: + vm.global[index].type = ValueType.IntegerArray; + vm.global[index].integerArray = new Array!int(dim); + break; + default: + throw new TypeMismatch(); + break; + } + } +} diff --git a/SMILEBASIC/compiler.d b/SMILEBASIC/compiler.d index d32b16e..10bd1cc 100644 --- a/SMILEBASIC/compiler.d +++ b/SMILEBASIC/compiler.d @@ -20,6 +20,21 @@ class Scope } class Compiler { + ValueType getType(wstring name) + { + wchar s = name[name.length - 1]; + switch(s) + { + case '$': + return ValueType.String; + case '#': + return ValueType.Double; + case '%': + return ValueType.Integer; + default: + return ValueType.Integer;//DEFINT時 + } + } Statements statements; this(Statements statements) { @@ -219,7 +234,33 @@ class Compiler breakAddr.address = code.length; s.breakAddr.address = code.length; } - + void compileVar(Var node, Scope sc) + { + foreach(Statement v ; node.define) + { + if(v.type == NodeType.DefineVariable) + { + DefineVariable var = cast(DefineVariable)v; + //TODO:local variable + defineGlobalVarIndex(var.name); + continue; + } + if(v.type == NodeType.DefineArray) + { + DefineArray var = cast(DefineArray)v; + int siz = 0; + foreach_reverse(Expression expr; var.dim) + { + compileExpression(expr); + siz++; + if(siz == 4) + break;//4次元まで(パーサーで除去するけど万が一に備えて + } + genCode(new NewArray(getType(var.name), var.dim.length, defineGlobalVarIndex(var.name))); + continue; + } + } + } void compileStatements(Statements statements, Scope sc) { foreach(Statement s ; statements.statements) @@ -314,6 +355,9 @@ class Compiler } genCode(s.continueAddr); break; + case NodeType.Var: + compileVar(cast(Var)i, s); + break; default: stderr.writeln("Compile:NotImpl ", i.type); } diff --git a/SMILEBASIC/main.d b/SMILEBASIC/main.d index 8b39052..c15f0d3 100644 --- a/SMILEBASIC/main.d +++ b/SMILEBASIC/main.d @@ -53,7 +53,9 @@ FOR I=0 TO 10 IF I==1 THEN CONTINUE ?I NEXT -VAR V +VAR V[10] +?V[0] +?\"ABC\"[1][0] GOSUB @A END @A diff --git a/SMILEBASIC/node.d b/SMILEBASIC/node.d index 9ebb255..c05b5f0 100644 --- a/SMILEBASIC/node.d +++ b/SMILEBASIC/node.d @@ -13,6 +13,7 @@ enum NodeType CallFunction, VoidExpression, UnaryOperator, + IndexExpressions, Statements, FunctionBody, @@ -31,6 +32,7 @@ enum NodeType Var, DefineVariable, DefineArray, + ArrayAssign, } abstract class Node { @@ -323,11 +325,37 @@ class DefineVariable : Statement class DefineArray : Statement { wstring name; - int[] dim; - this(wstring name, int[] dim) + Expression[] dim; + this(wstring name, Expression[] dim) { this.type = NodeType.DefineArray; this.name = name; this.dim = dim; } } +class IndexExpressions : Expression +{ + Expression[] expressions; + this() + { + this.type = NodeType.IndexExpressions; + this.expressions = new Expression[0]; + } + void addExpression(Expression expr) + { + this.expressions ~= expr; + } +} +class ArrayAssign : Statement +{ + wstring name; + IndexExpressions indexExpression; + Expression assignExpression; + this(wstring name, IndexExpressions expr, Expression assign) + { + this.type = NodeType.ArrayAssign; + this.name = name; + this.indexExpression = expr; + this.assignExpression = assign; + } +} diff --git a/SMILEBASIC/parser.d b/SMILEBASIC/parser.d index dd7c4e7..1aeb981 100644 --- a/SMILEBASIC/parser.d +++ b/SMILEBASIC/parser.d @@ -306,7 +306,7 @@ class Parser case TokenType.And: return 7;//AND,OR,XOR case TokenType.Or: - return 9-1;//AND,OR,XOR + return 9;//AND,OR,XOR case TokenType.Xor: return 9;//AND,OR,XOR case TokenType.Equal: @@ -327,6 +327,8 @@ class Parser case TokenType.IntDiv: case TokenType.Mod: return 3;//*,/,DIV,MOD + case TokenType.LBracket: + return 2;//合ってるか不明 // return 2;//-,NOT,! // return 1;//() default: @@ -483,6 +485,11 @@ class Parser node = assign(name); return node; } + if(token.type == TokenType.LBracket)//配列代入 + { + node = arrayAssign(name); + return node; + } //命令呼び出し } break; @@ -544,6 +551,48 @@ class Parser lex.popFront(); return node; } + IndexExpressions indexExpressions() + { + IndexExpressions ie = new IndexExpressions(); + while(true) + { + ie.addExpression(expression()); + auto token = lex.front(); + if(token.type == TokenType.Comma) + { + lex.popFront(); + continue; + } + if(token.type == TokenType.RBracket) + { + break; + } + syntaxError(); + break; + } + return ie; + } + ArrayAssign arrayAssign(wstring name) + { + lex.popFront(); + auto ie = indexExpressions(); + auto token = lex.front(); + if(token.type != TokenType.RBracket) + { + return null; + } + lex.popFront(); + token = lex.front(); + if(token.type != TokenType.Assign) + { + //=が欲しい + syntaxError(); + return null; + } + auto expr = expression(); + auto node = new ArrayAssign(name, ie, expr); + return node; + } Statement var() { Var var = new Var(); @@ -558,7 +607,14 @@ class Parser return null; } auto v = defineVar(); - var.addDefineVar(cast(DefineVariable)v); + if(v.type == NodeType.DefineVariable) + { + var.addDefineVar(cast(DefineVariable)v); + } + if(v.type == NodeType.DefineArray) + { + var.addDefineArray(cast(DefineArray)v); + } //VARの評価順は順番通り //VAR iden[=expr], if(token.type == TokenType.Comma) @@ -585,18 +641,32 @@ class Parser if(token.type == TokenType.LBracket) { lex.popFront(); + Expression[] dim = new Expression[0]; while(true) { expr = expression(); token = lex.front(); + if(token.type != TokenType.RBracket) + { + syntaxError(); + break; + } + dim ~= expr; + lex.popFront(); + break; } + DefineArray ary = new DefineArray(name, dim); + return ary; } - //VAR iden=expr - if(token.type == TokenType.Equal) + else { - lex.popFront(); - expr = expression(); - token = lex.front(); + //VAR iden=expr + if(token.type == TokenType.Equal) + { + lex.popFront(); + expr = expression(); + token = lex.front(); + } } DefineVariable node = new DefineVariable(name, expr); return node; @@ -727,6 +797,7 @@ class Parser auto exp = expression(); if(exp is null) { + lex.popFront(); syntaxError(); continue; } @@ -790,6 +861,12 @@ class Parser op.operator = token.type; lex.popFront(); op.item2 = term(order - 1, node); + if(tt == TokenType.LBracket) + { + //[演算子 + if(lex.front().type != TokenType.RBracket) syntaxError(); + lex.popFront(); + } token = lex.front(); version(none) write(tt, " "); diff --git a/SMILEBASIC/type.d b/SMILEBASIC/type.d index 3a46349..d79e82b 100644 --- a/SMILEBASIC/type.d +++ b/SMILEBASIC/type.d @@ -18,7 +18,9 @@ struct Value int integerValue; double doubleValue; wstring stringValue; - Array!int intArray; + Array!int integerArray; + Array!double doubleArray; + Array!wstring stringArray; } this(int value) {