basic interpret wip

This commit is contained in:
minjaesong
2020-06-02 07:22:04 +09:00
parent 1e0f122aff
commit e59c507ea0
5 changed files with 321 additions and 48 deletions

View File

@@ -1,20 +1,20 @@
// standard print functions
function print(s) {
vm.print(s);
sys.print(s);
}
function println(s) {
if (typeof s == "undefined")
vm.print("\n");
sys.print("\n");
else
vm.println(s);
sys.println(s);
}
function read() {
return vm.read();
return sys.read();
}
// ncurses-like terminal control
var con = new Object();
var con = {};
con.getch = function() {
return vm.readKey();
return sys.readKey();
};
con.move = function(y, x) {
print(String.fromCharCode(27,91)+y+";"+x+"H");
@@ -32,12 +32,12 @@ con.getyx = function() {
return graphics.getCursorYX();
};
con.hitterminate = function() { // ^C
vm.poke(-40, 1);
return (vm.peek(-41) == 31 && (vm.peek(-41) == 129 || vm.peek(-41) == 130));
sys.poke(-40, 1);
return (sys.peek(-41) == 31 && (sys.peek(-41) == 129 || sys.peek(-41) == 130));
};
con.hiteof = function() { // ^D
vm.poke(-40, 1);
return (vm.peek(-41) == 32 && (vm.peek(-41) == 129 || vm.peek(-41) == 130));
sys.poke(-40, 1);
return (sys.peek(-41) == 32 && (sys.peek(-41) == 129 || sys.peek(-41) == 130));
};
con.color_fore = function(n) { // 0..7; -1 for transparent
if (n < 0)
@@ -57,11 +57,11 @@ con.color_pair = function(fore, back) { // 0..255
};
Object.freeze(con);
// system management function
var sys = new Object();
sys.maxmem = function() {
return vm.peek(-65) | (vm.peek(-66) << 8) | (vm.peek(-67) << 16) | (vm.peek(-68) << 24);
var system = {};
system.maxmem = function() {
return sys.peek(-65) | (sys.peek(-66) << 8) | (sys.peek(-67) << 16) | (sys.peek(-68) << 24);
};
sys.halt = function() {
system.halt = function() {
exit();
};
Object.freeze(sys);
Object.freeze(system);

View File

@@ -176,7 +176,7 @@ for (var frames = 0; frames < height * divisor; frames++) {
}
}
var memstring = "USER RAM: " + ((vm.peek(-66) >> 2) + (vm.peek(-67) << 6) + (vm.peek(-68) << 14));
var memstring = "USER RAM: " + ((sys.peek(-66) >> 2) + (sys.peek(-67) << 6) + (sys.peek(-68) << 14));
if (memstring.length % 2 == 0) memstring += " Kbytes"; else memstring += " Kbytes";
var cy = Math.floor((yoff + height + 14) / 14);
var cx = Math.floor(((560 - 7*(memstring.length)) / 2) / 7);

View File

@@ -448,10 +448,18 @@ image[445]=[254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,
image[446]=[254,254,254,253,194,254,254,254,194,254,254,254,234,254,234,254,254,254,254,254,254,254,254,254,254,194,254,234,254,253,254,254,253,254,194,254,254,194,254,254,254,254,253,254,253,194,254,253,254,254,253,194,254,253,234,254,253,254,194,254,254,254,254,194,254,254,254,234,254,254,234,254,254,254,194,254,253,254,254,254,254,254,254,254,254,194,254,234,254,253,234,254,253,194,254,254,254,254,194,254,254,254,254,254,254,254,254,254,253,254,254,254,254,253,254,254,254,254,253,254,194,254,254,254,254,254,194,254,254,254,254,253,253,254,254,253,254,254,254,194,254,194,254,254,254,253,254,254,253,254,254,234,254,253,254,254,254,234,254,254,254,194,254,254,194,254,254,194,254,254,234,254,194,254,234,254,254,234,254,253,254,253,194,254,254,234,253,254,194,254,254,253,254,254,254,253,254,194,254,253,253,253,194,254,253,194,254,254,253,254,253,254,254,254,253,194,254,254,254,254,254,253,194,254,254,254,254,254,254,254,253,254,254,254,254,254,254,254,254,254,254,253,194,254,254,254,254,254,254,234,254,254,194,239,194,239,194,239,194,239,194,239,254,254,254,194,239,254,239,194,239,254,254,194,239,254,254,254,254,254,194,254,194,254,254,234,254,253,254,254,254,254,254,254,254,254,254,239,254,254,254,239,254,234,254,254,254,254,254,254,254,254,254,194,254,254,254,254,254,254,254,254,254,254,254,194,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,194,254,254,254,239,194,239,254,254,194,239,254,194,254,254,254,254,234,254,254,254,234,254,254,254,254,254,254,194,239,254,254,254,254,254,254,194,254,239,254,254,234,254,254,254,239,194,254,254,254,254,254,253,194,254,254,234,254,254,254,254,253,254,254,234,254,253,194,254,254,254,254,254,254,254,254,194,254,254,254,253,194,254,254,253,254,253,254,194,254,254,254,253,254,234,254,194,254,254,194,254,254,254,254,254,254,254,254,254,254,254,254,194,254,254,234,254,253,234,254,254,254,254,254,194,254,254,254,253,254,253,254,254,254,194,254,254,253,253,254,194,254,254,253,194,254,254,194,254,254,254,254,254,254,254,234,254,234,254,254,254,234,254,254,253,254,254,254,253,254,254,254,254,254,253,254,254,254,254,253,194,254,254,254,254,254,253,254,253,194,254,194,254,253,254,254,253,254,253,253,194,254,253,254,253,194,254,254,254,253,254,254,254,194,254,254,194,254];
image[447]=[253,254,254,254,254,254,254,254,254,253,254,254,254,254,254,254,254,194,254,254,254,194,253,254,254,254,254,254,194,254,254,194,254,254,254,253,254,254,254,194,254,194,254,234,254,254,234,254,194,254,254,254,254,254,254,234,254,254,254,254,194,254,254,254,194,254,254,254,253,254,254,254,254,254,254,194,254,254,254,194,254,254,194,254,254,254,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,194,254,254,254,234,254,194,254,254,254,254,194,254,254,254,254,254,253,254,253,254,254,254,254,254,194,254,254,253,234,253,254,253,254,254,253,254,253,194,254,194,254,194,254,253,254,253,254,254,234,253,254,254,253,254,254,254,254,254,254,253,254,234,254,253,254,254,254,254,254,253,254,254,254,194,254,254,254,254,253,254,254,254,254,254,194,254,254,253,234,254,253,254,253,254,254,254,253,254,254,254,253,253,254,253,254,253,234,254,254,253,254,234,253,253,254,254,254,254,253,254,254,194,253,254,254,254,254,194,254,254,254,194,253,254,254,254,254,254,254,254,254,194,254,254,254,254,239,254,254,254,254,254,254,254,254,194,254,254,239,254,254,234,254,254,194,254,254,254,254,254,253,254,254,254,254,254,254,254,254,254,254,194,254,254,194,254,254,254,254,254,254,254,254,194,254,254,254,254,254,254,239,194,239,194,254,254,254,254,254,254,254,254,254,234,254,254,234,254,254,254,254,254,234,254,254,254,239,194,254,254,254,254,254,254,254,239,254,254,254,254,254,239,194,254,239,254,254,254,239,194,254,254,254,254,254,254,254,254,254,234,239,194,239,254,239,194,254,239,194,254,254,239,254,254,194,254,254,254,254,254,254,254,254,254,254,194,254,234,254,254,253,254,254,253,234,254,254,194,254,253,254,254,254,254,234,254,254,194,253,234,254,254,254,253,254,254,254,254,254,254,254,254,254,254,254,254,234,254,254,254,254,254,254,234,254,254,254,254,194,254,254,194,254,254,254,254,254,254,254,254,254,253,254,254,254,253,254,234,254,254,254,254,194,254,254,194,254,194,253,254,254,253,254,194,253,254,253,253,254,254,253,253,254,253,253,234,254,253,254,253,254,253,254,254,234,254,254,254,254,254,254,254,194,254,254,194,254,253,234,254,234,254,254,194,254,254,254,254,254,254,254,194,254,254,254,254,254,254,194,254,253,254,253,234,254,254,254,253,253,254,254,253,254,194,254,254,253,254,254,254,254,254,254,254];
for (var y = 0; y < 448; y++) {
for (var x = 0; x < 560; x++) {
graphics.plotPixel(x, y, image[y][x]);
}
}
var indices = []; var i;
for (i = 0; i < 250880; i++) indices[i] = i;
for (i = indices.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var x = indices[i];
indices[i] = indices[j];
indices[j] = x;
}
for (i = 0; i < 250880; i++) {
var x = indices[i] % 560;
var y = (indices[i] / 560)|0;
graphics.plotPixel(x, y, image[y][x]);
}
con.color_fore(0);

View File

@@ -1,16 +1,33 @@
/*
NOTE: do not allow concatenation of commands!
Operators
; - When used by PRINT and INPUT, concatenates two printables; numbers will have one space between them while strings
will not.
, - Function argument separator
+ - Just as in JS; concatenates two strings
*/
var vmemsize = sys.maxmem() - 5236;
var vmemused = 0;
var vmemsize = system.maxmem() - 5236;
var cmdbuf = []; // index: line number
var cmdbufMemFootPrint = 0;
var prompt = "Ok";
var lang = {
syntaxfehler: "Syntax error"
var lang = {};
lang.syntaxfehler = function(line) {
if (typeof line == "undefined")
return "Syntax error";
return "Syntax error in " + line;
};
function getUsedMemSize() {
return cmdbufMemFootPrint; // + array's dimsize * 8 + variables' sizeof literal + functions' expression length
}
var reLineNum = /^[0-9]+ +[^0-9]/;
var reFloat = /^([\-+]?[0-9]*[.][0-9]+[eE]*[\-+0-9]*[fF]*|[\-+]?[0-9]+[.eEfF][0-9+\-]*[fF]?)$/;
var reDec = /^([\-+]?[0-9_]+)$/;
@@ -26,23 +43,83 @@ var tbasexit = false;
println("Terran BASIC 1.0 "+vmemsize+" bytes free");
println(prompt);
var basicFunctions = new Object();
var basicInterpreterStatus = {};
// variable object constructor
function BasicVar(linenum, literal, type) {
this.literal = literal;
this.type = type;
}
// DEFUN (GW-BASIC equiv. of DEF FN) constructor
function BasicFun(linenum, params, expression) {
this.params = params;
this.expression = expression;
}
// DIM (array) constructor
function BasicArr() {
var args = Array.from(arguments);
if (args.length == 1)
throw lang.syntaxfehler(args[0]);
else if (args.length == 0)
throw "InternalError: pass the line number!";
else {
// create nested array as defined
var dimsize = Number(args[1]);
var a = new Array(args[1]);
var internal = a;
for (var i = 2; i < args.length; i++) {
dimsize *= Number(args[i]);
var inner = new Array(args[i]);
internal.push(inner);
internal = inner;
}
this.array = a;
this.dimsize = dimsize;
}
}
basicInterpreterStatus.gosubStack = [];
basicInterpreterStatus.variables = {};
basicInterpreterStatus.defuns = {};
basicInterpreterStatus.builtin = {};
basicInterpreterStatus.builtin.print = function() {
var args = Array.from(arguments);
if (args.length == 0)
println();
else
println(args.join("\t"));
};
Object.freeze(basicInterpreterStatus.builtin);
var basicFunctions = {};
basicFunctions._isNumber = function(code) {
return (code >= 0x30 && code <= 0x39) || code == 0x2E;
};
basicFunctions._isParenOpen = function(code) {
return (code == 0x28 || code == 0x5B);
};
basicFunctions._isParenClose = function(code) {
return (code == 0x29 || code == 0x5D);
};
basicFunctions._isParen = function(code) {
return basicFunctions._isParenOpen(code) || basicFunctions._isParenClose(code);
};
basicFunctions._isSeparator = function(code) {
return code == 0x2C;
};
basicFunctions._isOperator = function(code) {
return (code == 0x21 || code == 0x23 || code == 0x25 || (code >= 0x2A && code <= 0x2D) || code == 0x2F || (code >= 0x3A && code <= 0x3E) || code == 0x5E || code == 0x7C);
return (code == 0x21 || code == 0x23 || code == 0x25 || code == 0x2A || code == 0x2B || code == 0x2D || code == 0x2E || code == 0x2F || (code >= 0x3C && code <= 0x3E) || code == 0x5E || code == 0x7C);
};
// @returns: line number for the next command, normally (lnum + 1); if GOTO or GOSUB was met, returns its line number
basicFunctions._interpretLine = function(lnum, cmd) {
var _debugprintStateTransition = false;
var tokens = [];
var modes = [];
var sb = "";
var mode = "literal"; // literal, escape, number, quote, quote_end, operator, limbo
var mode = "literal"; // literal, escape, number, quote, quote_end, operator, paren, sep, limbo
if (_debugprintStateTransition) println("Ln "+lnum+" cmd "+cmd);
// TOKENISE
// TODO add separator
for (var k = 0; k < cmd.length; k++) {
var char = cmd.charAt(k);
var charCode = cmd.charCodeAt(k);
@@ -51,7 +128,7 @@ basicFunctions._interpretLine = function(lnum, cmd) {
if (mode == "literal") {
if (0x22 == charCode) { // "
tokens.push(sb); sb = "";
tokens.push(sb); sb = ""; modes.push(mode);
mode = "quote";
}
/*else if (charCode == 0x5C) { // reverse solidus
@@ -59,13 +136,21 @@ basicFunctions._interpretLine = function(lnum, cmd) {
mode = "escape";
}*/
else if (basicFunctions._isOperator(charCode)) {
tokens.push(sb); sb = "" + char;
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "operator";
}
else if (basicFunctions._isParen(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "paren";
}
else if (" " == char) {
tokens.push(sb); sb = "";
tokens.push(sb); sb = ""; modes.push(mode);
mode = "limbo";
}
else if (basicFunctions._isSeparator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "sep";
}
else {
sb += char;
}
@@ -91,7 +176,7 @@ basicFunctions._interpretLine = function(lnum, cmd) {
}
else if ("quote" == mode) {
if (0x22 == charCode) {
tokens.push(sb); sb = "";
tokens.push(sb); sb = ""; modes.push(mode);
mode = "quote_end";
}
else {
@@ -114,19 +199,27 @@ basicFunctions._interpretLine = function(lnum, cmd) {
sb += char;
}
else if (" " == char) {
tokens.push(sb); sb = "";
tokens.push(sb); sb = ""; modes.push(mode);
mode = "limbo";
}
else if (basicFunctions._isOperator(charCode)) {
tokens.push(sb); sb = "" + char;
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "operator";
}
else if (0x22 == charCode) {
tokens.push(sb); sb = "" + char;
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "quote";
}
else if (basicFunctions._isParen(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "paren";
}
else if (basicFunctions._isSeparator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "sep";
}
else {
tokens.push(sb); sb = "" + char;
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "literal";
}
}
@@ -135,16 +228,24 @@ basicFunctions._interpretLine = function(lnum, cmd) {
sb += char;
}
else if (basicFunctions._isNumber(charCode)) {
tokens.push(sb); sb = "" + char;
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "number";
}
else if (" " == char) {
tokens.push(sb); sb = "";
tokens.push(sb); sb = ""; modes.push(mode);
mode = "limbo";
}
else if (basicFunctions._isParen(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "paren";
}
else if (basicFunctions._isSeparator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "sep";
}
else {
tokens.push(sb); sb = "" + char;
mode = "lteral";
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "literal";
}
}
else if ("limbo" == mode) {
@@ -163,11 +264,79 @@ basicFunctions._interpretLine = function(lnum, cmd) {
sb = "";
mode = "quote"
}
else if (basicFunctions._isParen(charCode)) {
sb = "";
mode = "paren";
}
else if (basicFunctions._isSeparator(charCode)) {
sb = "";
mode = "sep";
}
else {
sb = "" + char;
mode = "literal";
}
}
else if ("paren" == mode) {
if (char == " ") {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "limbo";
}
else if (basicFunctions._isNumber(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "number"
}
else if (basicFunctions._isOperator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "operator"
}
else if (0x22 == charCode) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "quote"
}
else if (basicFunctions._isParen(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "paren";
}
else if (basicFunctions._isSeparator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "sep";
}
else {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "literal";
}
}
else if ("sep" == mode) {
if (char == " ") {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "limbo";
}
else if (basicFunctions._isNumber(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "number"
}
else if (basicFunctions._isOperator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "operator"
}
else if (0x22 == charCode) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "quote"
}
else if (basicFunctions._isParen(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "paren";
}
else if (basicFunctions._isSeparator(charCode)) {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "sep";
}
else {
tokens.push(sb); sb = "" + char; modes.push(mode);
mode = "literal";
}
}
else {
throw "Unknown parser state: " + mode;
}
@@ -176,15 +345,18 @@ basicFunctions._interpretLine = function(lnum, cmd) {
}
if (sb.length > 0) {
tokens.push(sb);
tokens.push(sb); modes.push(mode);
}
// END TOKENISE
println(tokens.join("|"));
println(tokens.join("~"));
println(modes.join(" "));
return lnum + 1;
};
}; // end INTERPRETLINE
basicFunctions._basicList = function(v, i, arr) {
if (i < 10) print(" ");
if (i < 100) print(" ");
@@ -237,7 +409,16 @@ basicFunctions.renum = function(args) { // RENUM function
newcmdbuf[k] = "gosub " + linenumRelation[newcmdbuf[k].match(reNum)[0]];
}
}
cmdbuf = newcmdbuf.slice();
cmdbuf = newcmdbuf.slice(); // make shallow copy
// recalculate memory footprint
cmdbufMemFootPrint = 0;
cmdbuf.forEach(function(v, i, arr) {
cmdbufMemFootPrint += ("" + i).length + 1 + v.length;
});
};
basicFunctions.fre = function(args) {
println(vmemsize - getUsedMemSize());
};
basicFunctions.run = function(args) { // RUN function
var linenumber = 1;
@@ -258,22 +439,106 @@ basicFunctions.run = function(args) { // RUN function
};
Object.freeze(basicFunctions);
while (!tbasexit) {
var line = vm.read();
var line = sys.read();
line = line.trim();
cmdbufMemFootPrint += line.length;
if (reLineNum.test(line)) {
var i = line.indexOf(" ");
cmdbuf[line.slice(0, i)] = line.slice(i + 1, line.length);
}
else if (line.length > 0) {
cmdbufMemFootPrint -= line.length;
try {
var cmd = line.split(" ");
basicFunctions[cmd[0]](cmd);
}
catch (e) {
println(e);
println(lang.syntaxfehler);
println(lang.syntaxfehler());
}
println(prompt);
}
}
/*
digraph G {
start -> LITERAL
start -> LINENUMBER [label="reDec"]
LINENUMBER -> LINENUMBER [label="numbers"]
LINENUMBER -> limbo [label="space"]
LINENUMBER -> LITERAL [label="otherwise"]
LITERAL -> limbo [label="space"]
LITERAL -> OPERATOR [label="reOps"]
LITERAL -> ESCAPE [label="\\"]
LITERAL -> QUOTE [label="\""]
LITERAL -> PAREN [label="()[]"]
LITERAL -> SEP [label=","]
LITERAL -> LITERAL [label="otherwise"]
limbo -> NUMBER [label="numbers"]
limbo -> OPERATOR [label="reOps"]
limbo -> QUOTE [label="\""]
limbo -> LITERAL [label="otherwise"]
limbo -> PAREN [label="()[]"]
limbo -> SEP [label=","]
limbo -> limbo [label="space"]
ESCAPE -> LITERAL
QUOTE -> QUOTE_END [label="\""]
QUOTE -> QUOTE [label="otherwise"]
QUOTE_END -> limbo [label="space"]
QUOTE_END -> NUMBER [label="numbers"]
QUOTE_END -> OPERATOR [label="reOps"]
QUOTE_END -> PAREN [label="()[]"]
QUOTE_END -> SEP [label=","]
QUOTE_END -> LITERAL [label="otherwise"]
OPERATOR -> NUMBER [label="numbers"]
OPERATOR -> limbo [label="space"]
OPERATOR -> OPERATOR [label="reOps"]
OPERATOR -> PAREN [label="()[]"]
OPERATOR -> SEP [label=","]
OPERATOR -> LITERAL [label="otherwise"]
NUMBER -> NUMBER [label="numbers"]
NUMBER -> OPERATOR [label="reOps"]
NUMBER -> QUOTE [label="\""]
NUMBER -> limbo [label="space"]
NUMBER -> PAREN [label="()[]"]
NUMBER -> SEP [label=","]
NUMBER -> LITERAL [label="otherwise"]
PAREN -> PUSH_AND_PAREN [label="()[]"]
PAREN -> NUMBER [label="numbers"]
PAREN -> OPERATOR [label="reOps"]
PAREN -> QUOTE [label="\""]
PAREN -> limbo [label="space"]
PAREN -> SEP [label=","]
PAREN -> LITERAL [label="otherwise"]
SEP -> PAREN [label="()[]"]
SEP -> NUMBER [label="numbers"]
SEP -> OPERATOR [label="reOps"]
SEP -> QUOTE [label="\""]
SEP -> limbo [label="space"]
SEP -> PUSH_AND_SEP [label=","]
SEP -> LITERAL [label="otherwise"]
LITERAL -> end [label="\\n"]
NUMBER -> end [label="\\n"]
QUOTE_END -> end [label="\\n"]
OPERATOR -> end [label="\\n"]
PAREN -> end [label="\\n"]
start [shape=Mdiamond];
end [shape=Msquare];
concentrate=true;
}
*/

View File

@@ -50,7 +50,7 @@ object VMRunnerFactory {
private val bind = context.getBindings(ScriptContext.ENGINE_SCOPE)
init {
bind.put("vm", VMJSR223Delegate(vm)) // TODO use delegator class to access peripheral (do not expose VM itself)
bind.put("sys", VMJSR223Delegate(vm)) // TODO use delegator class to access peripheral (do not expose VM itself)
bind.put("graphics", GraphicsJSR223Delegate(vm))
//bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work...
//bind.put("nanotime", { System.nanoTime() })