From 312b2853f5baa6f7b063e58d81f833613ca74bf7 Mon Sep 17 00:00:00 2001 From: zodiac Date: Mon, 30 Mar 2009 16:55:00 +0000 Subject: [PATCH] Added "NEW" command to demo BASIC interpreter. Still not very useful, but we now have some of the basic framework in place to implement a minimalistic interpreter. git-svn-id: https://shellinabox.googlecode.com/svn/trunk@102 0da03de8-d603-11dd-86c2-0f8696b7b6f9 --- config.h | 2 +- configure | 2 +- configure.ac | 2 +- demo/demo.js | 137 ++++++++++++++++++++++++++++++++----------------- demo/demo.jspp | 137 ++++++++++++++++++++++++++++++++----------------- 5 files changed, 183 insertions(+), 97 deletions(-) diff --git a/config.h b/config.h index d567bc3..dfa081d 100644 --- a/config.h +++ b/config.h @@ -95,7 +95,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "101" +#define VCS_REVISION "102" /* Version number of package */ #define VERSION "2.5" diff --git a/configure b/configure index 247f763..3ec0c12 100755 --- a/configure +++ b/configure @@ -2056,7 +2056,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=101 +VCS_REVISION=102 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index a635936..02b30f1 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.5, markus@shellinabox.com) -VCS_REVISION=101 +VCS_REVISION=102 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) diff --git a/demo/demo.js b/demo/demo.js index bb91c8a..25527e3 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -69,8 +69,8 @@ // #define STATE_READLINE 3 // #define STATE_COMMAND 4 // #define STATE_EVAL 5 -// #define STATE_RUN 6 -// #define STATE_EXEC 7 +// #define STATE_EXEC 6 +// #define STATE_NEW_Y_N 7 function extend(subClass, baseClass) { function inheritance() { } @@ -87,55 +87,61 @@ function Demo(container) { extend(Demo, VT100); Demo.prototype.keysPressed = function(ch) { - this.keys += ch; + if (this.state == 6 /* STATE_EXEC */) { + for (var i = 0; i < ch.length; i++) { + var c = ch.charAt(i); + if (c == '\u0003') { + this.keys = ''; + this.error('Interrupted'); + return; + } + } + } + this.keys += ch; this.gotoState(this.state); }; Demo.prototype.gotoState = function(state, tmo) { - this.state = state; + this.state = state; if (!this.timer || tmo) { if (!tmo) { - tmo = 1; + tmo = 1; } - this.timer = setTimeout(function(demo) { - return function() { - demo.demo(); - }; - }(this), tmo); + this.nextTimer = setTimeout(function(demo) { + return function() { + demo.demo(); + }; + }(this), tmo); } }; Demo.prototype.demo = function() { var done = false; + this.nextTimer = undefined; while (!done) { var state = this.state; this.state = 0 /* STATE_IDLE */; switch (state) { case 1 /* STATE_INIT */: - this.doInit(); + done = this.doInit(); break; case 2 /* STATE_PROMPT */: - this.doPrompt(); + done = this.doPrompt(); break; case 3 /* STATE_READLINE */: - this.doReadLine(); - if (this.state == 3 /* STATE_READLINE */) { - done = true; - } + done = this.doReadLine(); break; case 4 /* STATE_COMMAND */: - this.doCommand(); + done = this.doCommand(); break; case 5 /* STATE_EVAL */: - this.doEval(); + done = this.doEval(); break; - case 6 /* STATE_RUN */: - this.doRun(); + case 6 /* STATE_EXEC */: + done = this.doExec(); break; - case 7 /* STATE_EXEC */: - if (this.doExec()) { - return; - } + case 7 /* STATE_NEW_Y_N */: + done = this.doNewYN(); break; case 0 /* STATE_IDLE */: default: @@ -143,15 +149,22 @@ Demo.prototype.demo = function() { break; } } - this.timer = undefined; + this.timer = this.nextTimer; + this.nextTimer = undefined; }; +Demo.prototype.ok = function() { + this.vt100('OK\r\n'); + this.gotoState(2 /* STATE_PROMPT */); +} + Demo.prototype.error = function(msg) { if (msg == undefined) { - msg = 'Syntax Error'; + msg = 'Syntax Error'; } this.vt100('\u0007? ' + msg + '\r\n'); this.gotoState(2 /* STATE_PROMPT */); + this.currentLineIndex = -1; }; Demo.prototype.doInit = function() { @@ -170,6 +183,7 @@ Demo.prototype.doInit = function() { 'Type HELP for a list of commands.\r\n' + '\r\n'); this.gotoState(2 /* STATE_PROMPT */); + return false; }; Demo.prototype.doPrompt = function() { @@ -178,6 +192,7 @@ Demo.prototype.doPrompt = function() { this.currentLineIndex = -1; this.vt100('> '); this.gotoState(3 /* STATE_READLINE */); + return false; }; Demo.prototype.doReadLine = function() { @@ -192,6 +207,7 @@ Demo.prototype.doReadLine = function() { } else if (ch == '\r' || ch == '\n') { this.vt100('\r\n'); this.gotoState(4 /* STATE_COMMAND */); + return false; } else if (ch == '\u0008' || ch == '\u007F') { if (this.line.length > 0) { this.line = this.line.substr(0, this.line.length - 1); @@ -212,6 +228,7 @@ Demo.prototype.doReadLine = function() { break; } } + return true; }; Demo.prototype.doCommand = function() { @@ -244,23 +261,23 @@ Demo.prototype.doCommand = function() { this.tokens = tokens; this.gotoState(5 /* STATE_EVAL */); } - tokens.reset(); } + tokens.reset(); + return false; }; Demo.prototype.doEval = function() { this.gotoState(2 /* STATE_PROMPT */); - var cmd = this.tokens.nextToken().toUpperCase(); + var cmd = this.tokens.nextToken().toUpperCase(); if (cmd == "HELP") { this.vt100('Supported commands:\r\n' + - ' HELP LIST RUN\r\n'); + ' HELP LIST NEW RUN\r\n'); } else if (cmd == "LIST") { if (this.tokens.nextToken() != undefined) { this.error(); - return false; } else { for (var i = 0; i < this.program.length; i++) { - var line = this.program[i]; + var line = this.program[i]; this.vt100('' + line.lineNumber()); line.tokens().reset(); for (var token; (token = line.tokens().nextToken()) != undefined; ) { @@ -270,39 +287,65 @@ Demo.prototype.doEval = function() { this.vt100('\r\n'); } } + } else if (cmd == "NEW") { + if (this.currentLineIndex >= 0) { + this.error('Cannot call NEW from a program'); + } else if (this.program.length == 0) { + this.ok(); + } else { + this.vt100('Do you really want to delete the program (y/N) '); + this.gotoState(7 /* STATE_NEW_Y_N */); + } } else if (cmd == "RUN") { if (this.tokens.nextToken() != undefined) { this.error(); + } else if (this.program.length > 0) { + this.currentLineIndex = 0; + this.gotoState(6 /* STATE_EXEC */); } else { - this.gotoState(6 /* STATE_RUN */); + this.ok(); } - return false; } else { this.error(); - return false; - } - return true; -}; - -Demo.prototype.doRun = function() { - if (this.program.length > 0) { - this.currentLineIndex = 0; - this.gotoState(7 /* STATE_EXEC */); } + return false; }; Demo.prototype.doExec = function() { this.tokens = this.program[this.currentLineIndex++].tokens(); this.tokens.reset(); - if (this.doEval()) { - if (this.currentLineIndex >= this.program.length) { - this.gotoState(2 /* STATE_PROMPT */); + this.doEval(); + if (this.currentLineIndex < 0) { + return false; + } else if (this.currentLineIndex >= this.program.length) { + this.ok(); + return false; + } else { + this.gotoState(6 /* STATE_EXEC */, 20); + return true; + } +}; + +Demo.prototype.doNewYN = function() { + for (var i = 0; i < this.keys.length; ) { + var ch = this.keys.charAt(i++); + if (ch == 'n' || ch == 'N' || ch == '\r' || ch == '\n') { + this.vt100('N\r\n'); + this.keys = this.keys.substr(i); + this.error('Aborted'); + return false; + } else if (ch == 'y' || ch == 'Y') { + this.vt100('Y\r\n'); + this.program.splice(0, this.program.length); + this.keys = this.keys.substr(i); + this.ok(); return false; } else { - this.gotoState(7 /* STATE_EXEC */, 20); - return true; + this.vt100('\u0007'); } } + this.gotoState(7 /* STATE_NEW_Y_N */); + return true; }; Demo.prototype.findLine = function(lineNumber) { diff --git a/demo/demo.jspp b/demo/demo.jspp index 538c609..56ddca0 100644 --- a/demo/demo.jspp +++ b/demo/demo.jspp @@ -69,8 +69,8 @@ #define STATE_READLINE 3 #define STATE_COMMAND 4 #define STATE_EVAL 5 -#define STATE_RUN 6 -#define STATE_EXEC 7 +#define STATE_EXEC 6 +#define STATE_NEW_Y_N 7 function extend(subClass, baseClass) { function inheritance() { } @@ -87,55 +87,61 @@ function Demo(container) { extend(Demo, VT100); Demo.prototype.keysPressed = function(ch) { - this.keys += ch; + if (this.state == STATE_EXEC) { + for (var i = 0; i < ch.length; i++) { + var c = ch.charAt(i); + if (c == '\u0003') { + this.keys = ''; + this.error('Interrupted'); + return; + } + } + } + this.keys += ch; this.gotoState(this.state); }; Demo.prototype.gotoState = function(state, tmo) { - this.state = state; + this.state = state; if (!this.timer || tmo) { if (!tmo) { - tmo = 1; + tmo = 1; } - this.timer = setTimeout(function(demo) { - return function() { - demo.demo(); - }; - }(this), tmo); + this.nextTimer = setTimeout(function(demo) { + return function() { + demo.demo(); + }; + }(this), tmo); } }; Demo.prototype.demo = function() { var done = false; + this.nextTimer = undefined; while (!done) { var state = this.state; this.state = STATE_IDLE; switch (state) { case STATE_INIT: - this.doInit(); + done = this.doInit(); break; case STATE_PROMPT: - this.doPrompt(); + done = this.doPrompt(); break; case STATE_READLINE: - this.doReadLine(); - if (this.state == STATE_READLINE) { - done = true; - } + done = this.doReadLine(); break; case STATE_COMMAND: - this.doCommand(); + done = this.doCommand(); break; case STATE_EVAL: - this.doEval(); - break; - case STATE_RUN: - this.doRun(); + done = this.doEval(); break; case STATE_EXEC: - if (this.doExec()) { - return; - } + done = this.doExec(); + break; + case STATE_NEW_Y_N: + done = this.doNewYN(); break; case STATE_IDLE: default: @@ -143,15 +149,22 @@ Demo.prototype.demo = function() { break; } } - this.timer = undefined; + this.timer = this.nextTimer; + this.nextTimer = undefined; }; +Demo.prototype.ok = function() { + this.vt100('OK\r\n'); + this.gotoState(STATE_PROMPT); +} + Demo.prototype.error = function(msg) { if (msg == undefined) { - msg = 'Syntax Error'; + msg = 'Syntax Error'; } this.vt100('\u0007? ' + msg + '\r\n'); this.gotoState(STATE_PROMPT); + this.currentLineIndex = -1; }; Demo.prototype.doInit = function() { @@ -170,6 +183,7 @@ Demo.prototype.doInit = function() { 'Type HELP for a list of commands.\r\n' + '\r\n'); this.gotoState(STATE_PROMPT); + return false; }; Demo.prototype.doPrompt = function() { @@ -178,6 +192,7 @@ Demo.prototype.doPrompt = function() { this.currentLineIndex = -1; this.vt100('> '); this.gotoState(STATE_READLINE); + return false; }; Demo.prototype.doReadLine = function() { @@ -192,6 +207,7 @@ Demo.prototype.doReadLine = function() { } else if (ch == '\r' || ch == '\n') { this.vt100('\r\n'); this.gotoState(STATE_COMMAND); + return false; } else if (ch == '\u0008' || ch == '\u007F') { if (this.line.length > 0) { this.line = this.line.substr(0, this.line.length - 1); @@ -212,6 +228,7 @@ Demo.prototype.doReadLine = function() { break; } } + return true; }; Demo.prototype.doCommand = function() { @@ -244,23 +261,23 @@ Demo.prototype.doCommand = function() { this.tokens = tokens; this.gotoState(STATE_EVAL); } - tokens.reset(); } + tokens.reset(); + return false; }; Demo.prototype.doEval = function() { this.gotoState(STATE_PROMPT); - var cmd = this.tokens.nextToken().toUpperCase(); + var cmd = this.tokens.nextToken().toUpperCase(); if (cmd == "HELP") { this.vt100('Supported commands:\r\n' + - ' HELP LIST RUN\r\n'); + ' HELP LIST NEW RUN\r\n'); } else if (cmd == "LIST") { if (this.tokens.nextToken() != undefined) { this.error(); - return false; } else { for (var i = 0; i < this.program.length; i++) { - var line = this.program[i]; + var line = this.program[i]; this.vt100('' + line.lineNumber()); line.tokens().reset(); for (var token; (token = line.tokens().nextToken()) != undefined; ) { @@ -270,39 +287,65 @@ Demo.prototype.doEval = function() { this.vt100('\r\n'); } } + } else if (cmd == "NEW") { + if (this.currentLineIndex >= 0) { + this.error('Cannot call NEW from a program'); + } else if (this.program.length == 0) { + this.ok(); + } else { + this.vt100('Do you really want to delete the program (y/N) '); + this.gotoState(STATE_NEW_Y_N); + } } else if (cmd == "RUN") { if (this.tokens.nextToken() != undefined) { this.error(); + } else if (this.program.length > 0) { + this.currentLineIndex = 0; + this.gotoState(STATE_EXEC); } else { - this.gotoState(STATE_RUN); + this.ok(); } - return false; } else { this.error(); - return false; - } - return true; -}; - -Demo.prototype.doRun = function() { - if (this.program.length > 0) { - this.currentLineIndex = 0; - this.gotoState(STATE_EXEC); } + return false; }; Demo.prototype.doExec = function() { this.tokens = this.program[this.currentLineIndex++].tokens(); this.tokens.reset(); - if (this.doEval()) { - if (this.currentLineIndex >= this.program.length) { - this.gotoState(STATE_PROMPT); + this.doEval(); + if (this.currentLineIndex < 0) { + return false; + } else if (this.currentLineIndex >= this.program.length) { + this.ok(); + return false; + } else { + this.gotoState(STATE_EXEC, 20); + return true; + } +}; + +Demo.prototype.doNewYN = function() { + for (var i = 0; i < this.keys.length; ) { + var ch = this.keys.charAt(i++); + if (ch == 'n' || ch == 'N' || ch == '\r' || ch == '\n') { + this.vt100('N\r\n'); + this.keys = this.keys.substr(i); + this.error('Aborted'); + return false; + } else if (ch == 'y' || ch == 'Y') { + this.vt100('Y\r\n'); + this.program.splice(0, this.program.length); + this.keys = this.keys.substr(i); + this.ok(); return false; } else { - this.gotoState(STATE_EXEC, 20); - return true; + this.vt100('\u0007'); } } + this.gotoState(STATE_NEW_Y_N); + return true; }; Demo.prototype.findLine = function(lineNumber) {