mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-02-21 06:29:02 +00:00
basic: fixed tty column count, added hex/octal
This commit is contained in:
parent
6c7e852748
commit
0fd04658cb
@ -2,7 +2,7 @@
|
|||||||
15 PRINT
|
15 PRINT
|
||||||
20 INPUT "WOULD YOU MIND TYPING IN YOUR NAME";A$
|
20 INPUT "WOULD YOU MIND TYPING IN YOUR NAME";A$
|
||||||
25 PRINT
|
25 PRINT
|
||||||
30 PRINT "THANKS, ";A$;"! THIS WILL BE FUN!"
|
30 PRINT "THANKS, ";A$;"! THIS WILL BE FUN!";CHR$(7)
|
||||||
35 PRINT
|
35 PRINT
|
||||||
40 INPUT "NOW TELL ME YOUR FAVORITE NUMBER";N
|
40 INPUT "NOW TELL ME YOUR FAVORITE NUMBER";N
|
||||||
45 PRINT
|
45 PRINT
|
||||||
|
@ -9,6 +9,7 @@ export interface BASICOptions {
|
|||||||
optionalWhitespace : boolean; // can "crunch" keywords?
|
optionalWhitespace : boolean; // can "crunch" keywords?
|
||||||
varNaming : 'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings
|
varNaming : 'A1'|'AA'|'*'; // only allow A0-9 for numerics, single letter for arrays/strings
|
||||||
tickComments : boolean; // support 'comments?
|
tickComments : boolean; // support 'comments?
|
||||||
|
hexOctalConsts : boolean; // support &H and &O integer constants?
|
||||||
validKeywords : string[]; // valid keywords (or null for accept all)
|
validKeywords : string[]; // valid keywords (or null for accept all)
|
||||||
validFunctions : string[]; // valid functions (or null for accept all)
|
validFunctions : string[]; // valid functions (or null for accept all)
|
||||||
validOperators : string[]; // valid operators (or null for accept all)
|
validOperators : string[]; // valid operators (or null for accept all)
|
||||||
@ -50,13 +51,14 @@ export class CompileError extends Error {
|
|||||||
|
|
||||||
// Lexer regular expression -- each (capture group) handles a different token type
|
// Lexer regular expression -- each (capture group) handles a different token type
|
||||||
|
|
||||||
const re_toks = /([0-9.]+[E][+-]?\d+)|(\d*[.]\d*[E0-9]*)|[0]*(\d+)|(['].*)|(\w+[$]?)|(".*?")|([<>]?[=<>])|([-+*/^,;:()?\\])|(\S+)/gi;
|
const re_toks = /([0-9.]+[E][+-]?\d+)|(\d*[.]\d*[E0-9]*)|[0]*(\d+)|&([OH][0-9A-F]+)|(['].*)|(\w+[$]?)|(".*?")|([<>]?[=<>])|([-+*/^,;:()?\\])|(\S+)/gi;
|
||||||
|
|
||||||
export enum TokenType {
|
export enum TokenType {
|
||||||
EOL = 0,
|
EOL = 0,
|
||||||
Float1,
|
Float1,
|
||||||
Float2,
|
Float2,
|
||||||
Int,
|
Int,
|
||||||
|
HexOctalInt,
|
||||||
Remark,
|
Remark,
|
||||||
Ident,
|
Ident,
|
||||||
String,
|
String,
|
||||||
@ -313,7 +315,7 @@ export class BASICParser {
|
|||||||
var tok = this.consumeToken();
|
var tok = this.consumeToken();
|
||||||
var tokstr = tok.str;
|
var tokstr = tok.str;
|
||||||
if (strlist.indexOf(tokstr) < 0) {
|
if (strlist.indexOf(tokstr) < 0) {
|
||||||
this.compileError(msg || `There should be one of "${strlist}" here.`);
|
this.compileError(msg || `There should be a ${strlist.map((s) => `"${s}"`).join(' or ')} here.`);
|
||||||
}
|
}
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
@ -343,6 +345,7 @@ export class BASICParser {
|
|||||||
line.label = tok.str;
|
line.label = tok.str;
|
||||||
this.curlabel = tok.str;
|
this.curlabel = tok.str;
|
||||||
break;
|
break;
|
||||||
|
case TokenType.HexOctalInt:
|
||||||
case TokenType.Float1:
|
case TokenType.Float1:
|
||||||
case TokenType.Float2:
|
case TokenType.Float2:
|
||||||
this.compileError(`Line numbers must be positive integers.`);
|
this.compileError(`Line numbers must be positive integers.`);
|
||||||
@ -384,7 +387,7 @@ export class BASICParser {
|
|||||||
if (this.opts.asciiOnly && !/^[\x00-\x7F]*$/.test(s))
|
if (this.opts.asciiOnly && !/^[\x00-\x7F]*$/.test(s))
|
||||||
this.dialectError(`non-ASCII characters`);
|
this.dialectError(`non-ASCII characters`);
|
||||||
// uppercase all identifiers, and maybe more
|
// uppercase all identifiers, and maybe more
|
||||||
if (i == TokenType.Ident || this.opts.uppercaseOnly)
|
if (i == TokenType.Ident || i == TokenType.HexOctalInt || this.opts.uppercaseOnly)
|
||||||
s = s.toUpperCase();
|
s = s.toUpperCase();
|
||||||
// un-crunch tokens?
|
// un-crunch tokens?
|
||||||
if (splitre) {
|
if (splitre) {
|
||||||
@ -396,7 +399,7 @@ export class BASICParser {
|
|||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (/^[0-9]+$/.test(s)) i = TokenType.Int;
|
if (/^[0-9]+$/.test(s)) i = TokenType.Int; // leftover might be integer
|
||||||
}
|
}
|
||||||
// add token to list
|
// add token to list
|
||||||
this.tokens.push({str: s, type: i, $loc:loc});
|
this.tokens.push({str: s, type: i, $loc:loc});
|
||||||
@ -543,12 +546,16 @@ export class BASICParser {
|
|||||||
parsePrimary(): Expr {
|
parsePrimary(): Expr {
|
||||||
let tok = this.consumeToken();
|
let tok = this.consumeToken();
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
|
case TokenType.HexOctalInt:
|
||||||
|
if (!this.opts.hexOctalConsts) this.dialectError(`hex/octal constants`);
|
||||||
|
let base = tok.str.startsWith('H') ? 16 : 8;
|
||||||
|
return { value: parseInt(tok.str.substr(1), base) };
|
||||||
case TokenType.Int:
|
case TokenType.Int:
|
||||||
case TokenType.Float1:
|
case TokenType.Float1:
|
||||||
case TokenType.Float2:
|
case TokenType.Float2:
|
||||||
return { value: this.parseNumber(tok.str)/*, $loc: tok.$loc*/ };
|
return { value: this.parseNumber(tok.str) };
|
||||||
case TokenType.String:
|
case TokenType.String:
|
||||||
return { value: stripQuotes(tok.str)/*, $loc: tok.$loc*/ };
|
return { value: stripQuotes(tok.str) };
|
||||||
case TokenType.Ident:
|
case TokenType.Ident:
|
||||||
if (tok.str == 'NOT') {
|
if (tok.str == 'NOT') {
|
||||||
let expr = this.parsePrimary();
|
let expr = this.parsePrimary();
|
||||||
@ -882,6 +889,7 @@ export const ECMA55_MINIMAL : BASICOptions = {
|
|||||||
maxDefArgs : 255,
|
maxDefArgs : 255,
|
||||||
maxStringLength : 255,
|
maxStringLength : 255,
|
||||||
tickComments : false,
|
tickComments : false,
|
||||||
|
hexOctalConsts : false,
|
||||||
validKeywords : ['BASE','DATA','DEF','DIM','END',
|
validKeywords : ['BASE','DATA','DEF','DIM','END',
|
||||||
'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT',
|
'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT',
|
||||||
'RANDOMIZE','READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO'
|
'RANDOMIZE','READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO'
|
||||||
@ -915,6 +923,7 @@ export const BASICODE : BASICOptions = {
|
|||||||
maxDefArgs : 255,
|
maxDefArgs : 255,
|
||||||
maxStringLength : 255,
|
maxStringLength : 255,
|
||||||
tickComments : false,
|
tickComments : false,
|
||||||
|
hexOctalConsts : false,
|
||||||
validKeywords : ['BASE','DATA','DEF','DIM','END',
|
validKeywords : ['BASE','DATA','DEF','DIM','END',
|
||||||
'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT',
|
'FOR','GO','GOSUB','GOTO','IF','INPUT','LET','NEXT','ON','OPTION','PRINT',
|
||||||
'READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO'
|
'READ','REM','RESTORE','RETURN','STEP','STOP','SUB','THEN','TO'
|
||||||
@ -949,6 +958,7 @@ export const ALTAIR_BASIC41 : BASICOptions = {
|
|||||||
maxDefArgs : 255,
|
maxDefArgs : 255,
|
||||||
maxStringLength : 255,
|
maxStringLength : 255,
|
||||||
tickComments : false,
|
tickComments : false,
|
||||||
|
hexOctalConsts : false,
|
||||||
validKeywords : [
|
validKeywords : [
|
||||||
'OPTION',
|
'OPTION',
|
||||||
'CONSOLE','DATA','DEF','DEFUSR','DIM','END','ERASE','ERROR',
|
'CONSOLE','DATA','DEF','DEFUSR','DIM','END','ERASE','ERROR',
|
||||||
@ -986,6 +996,7 @@ export const APPLESOFT_BASIC : BASICOptions = {
|
|||||||
maxDefArgs : 1, // TODO: no string FNs
|
maxDefArgs : 1, // TODO: no string FNs
|
||||||
maxStringLength : 255,
|
maxStringLength : 255,
|
||||||
tickComments : false,
|
tickComments : false,
|
||||||
|
hexOctalConsts : false,
|
||||||
validKeywords : [
|
validKeywords : [
|
||||||
'OPTION',
|
'OPTION',
|
||||||
'CLEAR','LET','DIM','DEF','GOTO','GOSUB','RETURN','ON','POP',
|
'CLEAR','LET','DIM','DEF','GOTO','GOSUB','RETURN','ON','POP',
|
||||||
@ -1028,6 +1039,7 @@ export const MODERN_BASIC : BASICOptions = {
|
|||||||
maxDefArgs : 255,
|
maxDefArgs : 255,
|
||||||
maxStringLength : 2048, // TODO?
|
maxStringLength : 2048, // TODO?
|
||||||
tickComments : true,
|
tickComments : true,
|
||||||
|
hexOctalConsts : true,
|
||||||
validKeywords : null, // all
|
validKeywords : null, // all
|
||||||
validFunctions : null, // all
|
validFunctions : null, // all
|
||||||
validOperators : null, // all
|
validOperators : null, // all
|
||||||
|
@ -43,8 +43,9 @@ export class TeleType {
|
|||||||
}
|
}
|
||||||
flushline() {
|
flushline() {
|
||||||
this.curline = null;
|
this.curline = null;
|
||||||
|
this.col = 0;
|
||||||
|
this.movePrintHead(false);
|
||||||
}
|
}
|
||||||
// TODO: support fixed-width window (use CSS grid?)
|
|
||||||
addtext(line: string, style: number) {
|
addtext(line: string, style: number) {
|
||||||
this.ensureline();
|
this.ensureline();
|
||||||
if (line.length) {
|
if (line.length) {
|
||||||
@ -80,17 +81,15 @@ export class TeleType {
|
|||||||
}
|
}
|
||||||
this.col += line.length;
|
this.col += line.length;
|
||||||
// wrap @ 80 columns (TODO: const)
|
// wrap @ 80 columns (TODO: const)
|
||||||
if (this.fixed && this.col >= this.ncols) this.newline();
|
if (this.fixed && this.col >= this.ncols) this.flushline();
|
||||||
this.ncharsout += line.length;
|
this.ncharsout += line.length;
|
||||||
this.movePrintHead(true);
|
this.movePrintHead(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newline() {
|
newline() {
|
||||||
this.flushline();
|
this.flushline();
|
||||||
this.col = 0;
|
this.ensureline();
|
||||||
this.movePrintHead(false);
|
|
||||||
}
|
}
|
||||||
// TODO: bug in interpreter where it tracks cursor position but maybe doesn't do newlines?
|
|
||||||
print(val: string) {
|
print(val: string) {
|
||||||
// split by newlines
|
// split by newlines
|
||||||
var lines = val.split("\n");
|
var lines = val.split("\n");
|
||||||
@ -239,7 +238,7 @@ export class TeleTypeWithKeyboard extends TeleType {
|
|||||||
s = s.toUpperCase();
|
s = s.toUpperCase();
|
||||||
this.addtext(s, 4);
|
this.addtext(s, 4);
|
||||||
this.flushline();
|
this.flushline();
|
||||||
this.resolveInput(s.split(',')); // TODO: should parse quotes, etc
|
this.resolveInput(s.split(','));
|
||||||
this.resolveInput = null;
|
this.resolveInput = null;
|
||||||
}
|
}
|
||||||
this.clearinput();
|
this.clearinput();
|
||||||
@ -253,7 +252,6 @@ export class TeleTypeWithKeyboard extends TeleType {
|
|||||||
super.ensureline();
|
super.ensureline();
|
||||||
}
|
}
|
||||||
scrollToBottom() {
|
scrollToBottom() {
|
||||||
// TODO: fails when lots of lines are scrolled
|
|
||||||
if (this.scrolldiv) {
|
if (this.scrolldiv) {
|
||||||
this.scrolling++;
|
this.scrolling++;
|
||||||
var top = $(this.page).height() + $(this.input).height();
|
var top = $(this.page).height() + $(this.input).height();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user