Added support for simple arithmetic.
git-svn-id: https://shellinabox.googlecode.com/svn/trunk@106 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
parent
f5a3c95a44
commit
15e4d5990f
2 changed files with 223 additions and 31 deletions
124
demo/demo.js
124
demo/demo.js
|
@ -171,7 +171,10 @@ Demo.prototype.error = function(msg) {
|
||||||
if (msg == undefined) {
|
if (msg == undefined) {
|
||||||
msg = 'Syntax Error';
|
msg = 'Syntax Error';
|
||||||
}
|
}
|
||||||
this.vt100((this.cursorX != 0 ? '\r\n' : '') + '\u0007? ' + msg + '\r\n');
|
this.vt100((this.cursorX != 0 ? '\r\n' : '') + '\u0007? ' + msg +
|
||||||
|
(this.currentLineIndex >= 0 ?
|
||||||
|
' in line ' + this.program[this.currentLineIndex].lineNumber() :
|
||||||
|
'') + '\r\n');
|
||||||
this.gotoState(2 /* STATE_PROMPT */);
|
this.gotoState(2 /* STATE_PROMPT */);
|
||||||
this.currentLineIndex = -1;
|
this.currentLineIndex = -1;
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -200,7 +203,7 @@ Demo.prototype.doPrompt = function() {
|
||||||
this.keys = '';
|
this.keys = '';
|
||||||
this.line = '';
|
this.line = '';
|
||||||
this.currentLineIndex = -1;
|
this.currentLineIndex = -1;
|
||||||
this.vt100('> ');
|
this.vt100((this.cursorX != 0 ? '\r\n' : '') + '> ');
|
||||||
this.gotoState(3 /* STATE_READLINE */);
|
this.gotoState(3 /* STATE_READLINE */);
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -297,8 +300,8 @@ Demo.prototype.doEval = function() {
|
||||||
} else if (token == "PRINT" || token == "?") {
|
} else if (token == "PRINT" || token == "?") {
|
||||||
this.doPrint();
|
this.doPrint();
|
||||||
} else if (token == "RUN") {
|
} else if (token == "RUN") {
|
||||||
if (this.tokens.nextToken() != null) {
|
if (this.tokens.peekToken() != null) {
|
||||||
this.error();
|
this.error('RUN does not take any parameters');
|
||||||
} else if (this.program.length > 0) {
|
} else if (this.program.length > 0) {
|
||||||
this.currentLineIndex = 0;
|
this.currentLineIndex = 0;
|
||||||
this.gotoState(6 /* STATE_EXEC */);
|
this.gotoState(6 /* STATE_EXEC */);
|
||||||
|
@ -306,7 +309,7 @@ Demo.prototype.doEval = function() {
|
||||||
this.ok();
|
this.ok();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.error();
|
this.error(token ? 'Unknown command: ' + token : undefined);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -317,21 +320,22 @@ Demo.prototype.doList = function() {
|
||||||
var token = this.tokens.nextToken();
|
var token = this.tokens.nextToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
if (!token.match(/[0-9]+/)) {
|
if (!token.match(/[0-9]+/)) {
|
||||||
return this.error();
|
return this.error('LIST can optional take a start and stop line number');
|
||||||
}
|
}
|
||||||
start = parseInt(token);
|
start = parseInt(token);
|
||||||
token = this.tokens.nextToken();
|
token = this.tokens.nextToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
if (token != ',') {
|
if (token != ',') {
|
||||||
return this.error();
|
return this.error('Comma expected');
|
||||||
}
|
}
|
||||||
token = this.tokens.nextToken();
|
token = this.tokens.nextToken();
|
||||||
if (!token || !token.match(/[0-9]+/)) {
|
if (!token || !token.match(/[0-9]+/)) {
|
||||||
return this.error();
|
return this.error(
|
||||||
|
'LIST can optionally take a start and stop line number');
|
||||||
}
|
}
|
||||||
stop = token.parseInt(token);
|
stop = token.parseInt(token);
|
||||||
if (stop < start) {
|
if (stop < start) {
|
||||||
return this.error();
|
return this.error('Start line number has to come before stop');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,6 +474,77 @@ Demo.prototype.findLine = function(lineNumber) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.expr = function() {
|
Demo.prototype.expr = function() {
|
||||||
|
var value = this.term();
|
||||||
|
while (value) {
|
||||||
|
var token = this.tokens.peekToken();
|
||||||
|
if (token != '+' && token != '-') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.tokens.consume();
|
||||||
|
var v = this.term();
|
||||||
|
if (!v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (value.type() != v.type()) {
|
||||||
|
if (value.type() != 0 /* TYPE_STRING */) {
|
||||||
|
value = new this.Value(0 /* TYPE_STRING */, ''+value.val(), ''+value.val());
|
||||||
|
}
|
||||||
|
if (v.type() != 0 /* TYPE_STRING */) {
|
||||||
|
v = new this.Value(0 /* TYPE_STRING */, ''+v.val(), ''+v.val());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token == '-') {
|
||||||
|
if (value.type() == 0 /* TYPE_STRING */) {
|
||||||
|
return this.error('Cannot subtract strings');
|
||||||
|
}
|
||||||
|
v = value.val() - v.val();
|
||||||
|
} else {
|
||||||
|
v = value.val() + v.val();
|
||||||
|
}
|
||||||
|
if (v == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(value.type(), ''+v, v);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.term = function() {
|
||||||
|
var value = this.factor();
|
||||||
|
while (value) {
|
||||||
|
var token = this.tokens.peekToken();
|
||||||
|
if (token != '*' && token != '/' && token != '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.tokens.consume();
|
||||||
|
var v = this.factor();
|
||||||
|
if (!v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (value.type() != 1 /* TYPE_NUMBER */ || v.type() != 1 /* TYPE_NUMBER */) {
|
||||||
|
return this.error('Cannot multiply or divide strings');
|
||||||
|
}
|
||||||
|
if (token == '*') {
|
||||||
|
v = value.val() * v.val();
|
||||||
|
} else {
|
||||||
|
v = value.val() / v.val();
|
||||||
|
if (token == '\\') {
|
||||||
|
if (v < 0) {
|
||||||
|
v = -Math.floor(-v);
|
||||||
|
} else {
|
||||||
|
v = Math.floor( v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (v == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(1 /* TYPE_NUMBER */, ''+v, v);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.factor = function() {
|
||||||
var token = this.tokens.nextToken();
|
var token = this.tokens.nextToken();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return token;
|
return token;
|
||||||
|
@ -478,7 +553,18 @@ Demo.prototype.expr = function() {
|
||||||
var value = undefined;
|
var value = undefined;
|
||||||
var str;
|
var str;
|
||||||
if ((str = token.match(/^"(.*)"/)) != null) {
|
if ((str = token.match(/^"(.*)"/)) != null) {
|
||||||
value = new this.Value(0 /* TYPE_STRING */, str[1]);
|
value = new this.Value(0 /* TYPE_STRING */, str[1], str[1]);
|
||||||
|
} else if (token.match(/^[0-9]/)) {
|
||||||
|
var number;
|
||||||
|
if (token.match(/^[0-9]*$/)) {
|
||||||
|
number = parseInt(token);
|
||||||
|
} else {
|
||||||
|
number = parseFloat(token);
|
||||||
|
}
|
||||||
|
if (number == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(1 /* TYPE_NUMBER */, token, number);
|
||||||
} else {
|
} else {
|
||||||
return this.error();
|
return this.error();
|
||||||
}
|
}
|
||||||
|
@ -615,11 +701,21 @@ Demo.prototype.Line.prototype.sort = function(a, b) {
|
||||||
return a.lineNumber_ - b.lineNumber_;
|
return a.lineNumber_ - b.lineNumber_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.Value = function(type, str) {
|
Demo.prototype.Value = function(type, str, val) {
|
||||||
this.type = type;
|
this.t = type;
|
||||||
this.str = str;
|
this.s = str;
|
||||||
|
this.v = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.Value.prototype.type = function() {
|
||||||
|
return this.t;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.Value.prototype.val = function() {
|
||||||
|
return this.v;
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.Value.prototype.toString = function() {
|
Demo.prototype.Value.prototype.toString = function() {
|
||||||
return this.str;
|
return this.s;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
122
demo/demo.jspp
122
demo/demo.jspp
|
@ -171,7 +171,10 @@ Demo.prototype.error = function(msg) {
|
||||||
if (msg == undefined) {
|
if (msg == undefined) {
|
||||||
msg = 'Syntax Error';
|
msg = 'Syntax Error';
|
||||||
}
|
}
|
||||||
this.vt100((this.cursorX != 0 ? '\r\n' : '') + '\u0007? ' + msg + '\r\n');
|
this.vt100((this.cursorX != 0 ? '\r\n' : '') + '\u0007? ' + msg +
|
||||||
|
(this.currentLineIndex >= 0 ?
|
||||||
|
' in line ' + this.program[this.currentLineIndex].lineNumber() :
|
||||||
|
'') + '\r\n');
|
||||||
this.gotoState(STATE_PROMPT);
|
this.gotoState(STATE_PROMPT);
|
||||||
this.currentLineIndex = -1;
|
this.currentLineIndex = -1;
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -297,8 +300,8 @@ Demo.prototype.doEval = function() {
|
||||||
} else if (token == "PRINT" || token == "?") {
|
} else if (token == "PRINT" || token == "?") {
|
||||||
this.doPrint();
|
this.doPrint();
|
||||||
} else if (token == "RUN") {
|
} else if (token == "RUN") {
|
||||||
if (this.tokens.nextToken() != null) {
|
if (this.tokens.peekToken() != null) {
|
||||||
this.error();
|
this.error('RUN does not take any parameters');
|
||||||
} else if (this.program.length > 0) {
|
} else if (this.program.length > 0) {
|
||||||
this.currentLineIndex = 0;
|
this.currentLineIndex = 0;
|
||||||
this.gotoState(STATE_EXEC);
|
this.gotoState(STATE_EXEC);
|
||||||
|
@ -306,7 +309,7 @@ Demo.prototype.doEval = function() {
|
||||||
this.ok();
|
this.ok();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.error();
|
this.error(token ? 'Unknown command: ' + token : undefined);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -317,21 +320,22 @@ Demo.prototype.doList = function() {
|
||||||
var token = this.tokens.nextToken();
|
var token = this.tokens.nextToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
if (!token.match(/[0-9]+/)) {
|
if (!token.match(/[0-9]+/)) {
|
||||||
return this.error();
|
return this.error('LIST can optional take a start and stop line number');
|
||||||
}
|
}
|
||||||
start = parseInt(token);
|
start = parseInt(token);
|
||||||
token = this.tokens.nextToken();
|
token = this.tokens.nextToken();
|
||||||
if (token) {
|
if (token) {
|
||||||
if (token != ',') {
|
if (token != ',') {
|
||||||
return this.error();
|
return this.error('Comma expected');
|
||||||
}
|
}
|
||||||
token = this.tokens.nextToken();
|
token = this.tokens.nextToken();
|
||||||
if (!token || !token.match(/[0-9]+/)) {
|
if (!token || !token.match(/[0-9]+/)) {
|
||||||
return this.error();
|
return this.error(
|
||||||
|
'LIST can optionally take a start and stop line number');
|
||||||
}
|
}
|
||||||
stop = token.parseInt(token);
|
stop = token.parseInt(token);
|
||||||
if (stop < start) {
|
if (stop < start) {
|
||||||
return this.error();
|
return this.error('Start line number has to come before stop');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,6 +474,77 @@ Demo.prototype.findLine = function(lineNumber) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.expr = function() {
|
Demo.prototype.expr = function() {
|
||||||
|
var value = this.term();
|
||||||
|
while (value) {
|
||||||
|
var token = this.tokens.peekToken();
|
||||||
|
if (token != '+' && token != '-') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.tokens.consume();
|
||||||
|
var v = this.term();
|
||||||
|
if (!v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (value.type() != v.type()) {
|
||||||
|
if (value.type() != TYPE_STRING) {
|
||||||
|
value = new this.Value(TYPE_STRING, ''+value.val(), ''+value.val());
|
||||||
|
}
|
||||||
|
if (v.type() != TYPE_STRING) {
|
||||||
|
v = new this.Value(TYPE_STRING, ''+v.val(), ''+v.val());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token == '-') {
|
||||||
|
if (value.type() == TYPE_STRING) {
|
||||||
|
return this.error('Cannot subtract strings');
|
||||||
|
}
|
||||||
|
v = value.val() - v.val();
|
||||||
|
} else {
|
||||||
|
v = value.val() + v.val();
|
||||||
|
}
|
||||||
|
if (v == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(value.type(), ''+v, v);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.term = function() {
|
||||||
|
var value = this.factor();
|
||||||
|
while (value) {
|
||||||
|
var token = this.tokens.peekToken();
|
||||||
|
if (token != '*' && token != '/' && token != '\\') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.tokens.consume();
|
||||||
|
var v = this.factor();
|
||||||
|
if (!v) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (value.type() != TYPE_NUMBER || v.type() != TYPE_NUMBER) {
|
||||||
|
return this.error('Cannot multiply or divide strings');
|
||||||
|
}
|
||||||
|
if (token == '*') {
|
||||||
|
v = value.val() * v.val();
|
||||||
|
} else {
|
||||||
|
v = value.val() / v.val();
|
||||||
|
if (token == '\\') {
|
||||||
|
if (v < 0) {
|
||||||
|
v = -Math.floor(-v);
|
||||||
|
} else {
|
||||||
|
v = Math.floor( v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (v == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(TYPE_NUMBER, ''+v, v);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.factor = function() {
|
||||||
var token = this.tokens.nextToken();
|
var token = this.tokens.nextToken();
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return token;
|
return token;
|
||||||
|
@ -478,7 +553,18 @@ Demo.prototype.expr = function() {
|
||||||
var value = undefined;
|
var value = undefined;
|
||||||
var str;
|
var str;
|
||||||
if ((str = token.match(/^"(.*)"/)) != null) {
|
if ((str = token.match(/^"(.*)"/)) != null) {
|
||||||
value = new this.Value(TYPE_STRING, str[1]);
|
value = new this.Value(TYPE_STRING, str[1], str[1]);
|
||||||
|
} else if (token.match(/^[0-9]/)) {
|
||||||
|
var number;
|
||||||
|
if (token.match(/^[0-9]*$/)) {
|
||||||
|
number = parseInt(token);
|
||||||
|
} else {
|
||||||
|
number = parseFloat(token);
|
||||||
|
}
|
||||||
|
if (number == NaN) {
|
||||||
|
return this.error('Numeric range error');
|
||||||
|
}
|
||||||
|
value = new this.Value(TYPE_NUMBER, token, number);
|
||||||
} else {
|
} else {
|
||||||
return this.error();
|
return this.error();
|
||||||
}
|
}
|
||||||
|
@ -615,11 +701,21 @@ Demo.prototype.Line.prototype.sort = function(a, b) {
|
||||||
return a.lineNumber_ - b.lineNumber_;
|
return a.lineNumber_ - b.lineNumber_;
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.Value = function(type, str) {
|
Demo.prototype.Value = function(type, str, val) {
|
||||||
this.type = type;
|
this.t = type;
|
||||||
this.str = str;
|
this.s = str;
|
||||||
|
this.v = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.Value.prototype.type = function() {
|
||||||
|
return this.t;
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.prototype.Value.prototype.val = function() {
|
||||||
|
return this.v;
|
||||||
};
|
};
|
||||||
|
|
||||||
Demo.prototype.Value.prototype.toString = function() {
|
Demo.prototype.Value.prototype.toString = function() {
|
||||||
return this.str;
|
return this.s;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue