EDIT.... disconnected the script.... it wasn't behaving in some folks browsers as I would have liked.
<\p> // Copyright 2022 CJ Veniot // Derivative of wwwbasic.js (https://github.com/google/wwwbasic/blob/master/wwwbasic.js) // subject to the same license as the source last committed on Github Dec 27, 2018 // // Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. 'use strict'; var sub_check = 0; var fn_check = 0; var draw_angle = 0; var keyState = {}; var keyPressed = 0; const gmap = new Map(); var page0; var page1; var page2; var constants_list=''; var NoEekOnSkip=0; var SleepUntilKey=0; var openwindow; var autodisplay=1; var display_now=0; var loop_count= 0; var spool_name=''; var spool_text=''; var hiddenElement = document.createElement('a'); //var acontext = new (window.AudioContext || window.webkitAudioContext)(); var globalAudioContext; var sndwave = "sine"; var sndfade = "exponential"; var audio_queue = []; var audio_queue_timer = 0; // https://stackoverflow.com/questions/69516768/web-audio-api-sound-interaction-stops-working-after-a-while class Audio { constructor() { // instantiate web audio api object // create gain node, gain corresponds with volume this.gainNode = globalAudioContext.createGain(); //this.gainNode.gain.setValueAtTime(0.8, 0); // allows volume to decrease with time // this.gainNode.gain.exponentialRampToValueAtTime(0.001, globalAudioContext.currentTime ); } createNotes(f,d) { let oscillator = globalAudioContext.createOscillator(); oscillator.type=sndwave; this.gainNode.gain.setValueAtTime(64/(Math.log(f)**2), globalAudioContext.currentTime); oscillator.frequency.setValueAtTime(f, globalAudioContext.currentTime ); if (sndfade=='no') {this.gainNode.gain.setValueAtTime(0.001, globalAudioContext.currentTime + d/18.2 );} else if (sndfade=='linear') {this.gainNode.gain.linearRampToValueAtTime(0.001, globalAudioContext.currentTime + d/18.2 );} else {this.gainNode.gain.exponentialRampToValueAtTime(0.001, globalAudioContext.currentTime + d/18.2 );} oscillator.connect(this.gainNode); this.gainNode.connect(globalAudioContext.destination); oscillator.start(0); oscillator.stop(globalAudioContext.currentTime + d/18.2 ); } } var g; var o; //var o; var curr_mode; var curr_width; var curr_height; var readme_modes = [ [0, 640, 200, 16], [1, 320, 200, 4], [2, 640, 200, 2], [3, 640, 200, 16], [4, 0, 0, 0], [5, 0, 0, 0], [6, 0, 0, 0], [7, 320, 200, 16], [8, 640, 200, 16], [9, 640, 350, 16], [10, 640, 350, 16], [11, 640, 480, 2], [12, 640, 480, 16], [13, 320, 200, 256], [14, 320, 200, 256], [15, 320, 200, 256], [16, 320, 200, 256], [17, 320, 200, 256], [23, 320, 200, 0], [24, 320, 200, 0], [25, 320, 200, 0], [26, 320, 200, 0], [27, 320, 200, 0] ]; (function() { var DYNAMIC_HEAP_SIZE = 1024 * 1024 * 16; var STACK_SIZE = 64 * 1024; var MAX_DIMENSIONS = 7; var BLACK = 0xff000000; var WHITE = 0xffffffff; var SIMPLE_TYPE_INFO = { 'byte': {array: 'Int8Array', size: 1, shift: 0, view: 'b'}, 'ubyte': {array: 'Uint8Array', size: 1, shift: 0, view: 'ub'}, 'short': {array: 'Int16Array', size: 2, shift: 1, view: 'i1'}, 'ushort': {array: 'Uint16Array', size: 2, shift: 1, view: 'iu1'}, 'long': {array: 'Int32Array', size: 4, shift: 2, view: 'i'}, 'ulong': {array: 'Uint32Array', size: 4, shift: 2, view: 'iu'}, 'single': {array: 'Float64Array', size: 8, shift: 3, view: 's'}, 'double': {array: 'Float64Array', size: 8, shift: 3, view: 'd'}, 'string': {array: 'Array', size: 1, shift: 0, view: 'str'}, }; var IMPLICIT_TYPE_MAP = { '$': 'string', '%%': 'byte', '~%%': 'ubyte', '%': 'short', '~%': 'ushort', '&': 'long', '~&': 'ulong', '!': 'single', '#': 'double', }; function NextChar(ch) { return String.fromCharCode(ch.charCodeAt(0) + 1); } function RenderFont(ctx, height) { var data = new Uint8Array(256 * 8 * height); var pos = 0; for (var i = 0; i < 256; ++i) { ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 16, 32); ctx.textBaseline = 'top'; ctx.font = 'bold 16px monospace'; ctx.save(); ctx.scale(1, height / 16); ctx.fillStyle = '#fff'; ctx.fillText(CHARSET.charAt(i), 0, 0); ctx.restore(); var pix = ctx.getImageData(0, 0, 8, height); var pdata = pix.data; for (var j = 0; j < pdata.length; j += 4) { var level = pdata[j] * 0.1140 + pdata[j + 1] * 0.5870 + pdata[j + 2] * 0.2989; data[pos++] = level > 128 ? 255 : 0; } } return data; } function LoadFont(s, dup) { var data = new Uint8Array(s.length * dup); var pos = 0; for (var i = 0; i < 256; ++i) { var row = Math.floor(i / 8); var col = i % 8; for (var y = 0; y < 8; ++y) { for (var d = 0; d < dup; ++d) { for (var x = 0; x < 8; ++x) { data[pos++] = s[x + y * 8 * 8 + col * 8 + row * 64 * 8] != ' ' ? 255 : 0; } } } } return data; } function CreateFont(ctx, height) { if (height == 8) { return LoadFont(FONT8, 1); } else if (height == 16) { return LoadFont(FONT8, 2); } else { return RenderFont(ctx, height); } } function Interpret(code, canvas, from_tag) { // Display Info (in browser only). var screen_mode = 0; var screen_bpp = 4; var text_width = 80; var text_height = 60; var font_height = 16; var screen_aspect = 1; var font_data; var ctx; var display; var display_data; var scale_canvas; function SetupDisplay(width, height, aspect, fheight) { if (!canvas) { return; } ctx = canvas.getContext('2d', { alpha: false }); display = ctx.createImageData(width, height); display_data = new Uint32Array(display.data.buffer); if (!scale_canvas) { scale_canvas = document.createElement('canvas'); } scale_canvas.width = width; scale_canvas.height = height; text_width = Math.floor(width / 8); text_height = Math.floor(height / fheight); screen_aspect = aspect; font_height = fheight; var sctx = scale_canvas.getContext('2d', { alpha: false}); font_data = CreateFont(sctx, font_height); } Screen(0); var debugging_mode = typeof debug == 'boolean' && debug; // Parsing and Run State. var labels = {}; var data_labels = {}; var flow = []; var types = {}; var functions = {}; var global_vars = {}; var vars = global_vars; var allocated = 0; var const_count = 0; var temp_count = 0; var inside_type = false; var inside_function = false; var var_decls = ''; var data = []; var data_pos = 0; var ops = []; var curop = ''; var ip = 0; var function_define_pos = 0; var function_old_allocated = 0; var function_name = null; // Call stack var stack = 0; var sp = 0; var bp = 0; // Input State var keys = []; var input_string = ''; var mouse_x = 0; var mouse_y = 0; var mouse_buttons = 0; var mouse_wheel = 0; var mouse_clip = 0; // Language Options var option_base = 0; var option_explicit = false; // Variable declaration defaults. var letter_default = {}; // Default is single. var i = 'a'; do { letter_default[i] = 'single'; i = NextChar(i); } while (i != 'z'); // Yield State var yielding = 0; var quitting = 0; var delay = 0; // Drawing and Console State var color_map; var reverse_color_map; var fg_id; var bg_id; var fg_color = WHITE; var bg_color = BLACK; // cjv: canvas background var text_x = 0; var text_y = 0; var pen_x = 0; var pen_y = 0; const toklist = [ ':', ';', ',', '(', ')', '{', '}', '[', ']', '+=', '-=', '*=', '/=', '\\=', '^=', '&=', '+', '-', '*', '/', '\\', '^', '&', '.', '<=', '>=', '<>', '=>', '=', '<', '>', '@', '\n', ]; code = code.replace(/\r/g, ' '); code = code.replace(/\t/g, ' '); if (from_tag) { code = code.replace(/</g, '<'); code = code.replace(/>/g, '>'); code = code.replace(/&/g, '&'); } var tok = null; var tok_count = 0; var line = canvas ? 0 : 1; function Next() { tok = ''; tok_count++; for (;;) { while (code.substr(0, 1) == ' ' || code.substr(0, 1) == '\t') { if (tok != '') { return; } code = code.substr(1); } if (code.search(/^_[ \t]*('[^\n]*)?\n/) != -1) { if (tok != '') { return; } code = code.substr(code.search('\n') + 1); ++line; // cjv continue; } if (code.substr(0, 1) == '\'') { if (tok != '') { return; } while (code.length > 0 && code.substr(0, 1) != '\n') { code = code.substr(1); } continue; } if (code.substr(0, 1) == '"') { if (tok != '') { return; } tok = '"'; code = code.substr(1); while (code.length > 0 && code.substr(0, 1) != '"') { if (code.substr(0, 1) == '\n') { // Allow strings to cut off at end of line. // GW-Basic seems to allow it. tok += '"'; return; } tok += code.substr(0, 1); code = code.substr(1); } tok += '"'; code = code.substr(1); return; } if (tok == '' && /[.0-9][#]?/.test(code.substr(0, 1))) { var n = code.match(/^([0-9]*([.][0-9]*)?([eE][+-]?[0-9]+)?[#]?)/); if (n === null) { Throw('Bad number'); } tok = n[1]; code = code.substr(tok.length); if (tok[tok.length - 1] == '#') { tok = tok.substr(0, tok.length - 1); } return; } for (var i = 0; i < toklist.length; ++i) { if (code.substr(0, toklist[i].length) == toklist[i]) { if (tok != '') { if (code.substr(0, 1) == '&' && code.substr(code.length - 1) != '$') { tok += '&'; code = code.substr(1); } return; } tok = toklist[i]; code = code.substr(toklist[i].length); if (tok == '\n') { ++line; tok = 'Monday, April 21, 2025
A Little expriment. If this works well enough I might be able to get some fun little applets on the blog.
New.BAS 15 (prod 2025-04-21 19:03 utc)
';
} else if (tok == '&' && code.substr(0, 1).toLowerCase() == 'h') {
code = code.substr(1);
var n = code.match(/^([0-9a-fA-F]+)/);
if (n === null) {
Throw('Bad hex number');
}
tok = '0x' + n[1];
code = code.substr(n[1].length);
} else if (tok == '&' && code.substr(0, 1).toLowerCase() == 'o') {
code = code.substr(1);
var n = code.match(/^([0-7]+)/);
if (n === null) {
Throw('Bad octal number');
}
tok = (+('0o' + n[1])).toString();
code = code.substr(n[1].length);
} else if (tok == '&' && code.substr(0, 1).toLowerCase() == 'b') {
code = code.substr(1);
var n = code.match(/^([0-1]+)/);
if (n === null) {
Throw('Bad binary number');
}
tok = '0b' + n[1];
code = code.substr(n[1].length);
}
return;
}
}
tok += code.substr(0, 1).toLowerCase();
code = code.substr(1);
if (code == '') {
return;
}
}
}
Next();
function ConsumeData() {
var quote = false;
var had_quote = false;
var item = '';
for (;;) {
var ch = code.substr(0, 1);
if (ch == '\n' || ch == '') {
if (!had_quote) {
if (!quote) {
item = item.trim();
}
data.push(item);
}
break;
}
else if (quote==false && item.trim()=='' && ch=='&') {item += '0';}
else if (quote==false && item.trim()=='0' && /^([hH])$/.test(ch) ) {item += 'x';}
else if (ch == '"') {
if (quote) {
data.push(item);
item = '';
quote = false;
had_quote = true;
} else {
quote = true;
if (item.search(/[^ \t]/) != -1) {
Throw('Data statement extra text: "' + item + '"');
}
item = '';
}
} else if (ch == ',') {
if (!quote) {
if (!had_quote) {
data.push(item.trim());
} else {
had_quote = false;
if (item.search(/[^ \t]/) != -1) {
Throw('Data statement extra text: "' + item + '"');
}
}
item = '';
} else {
item += ',';
}
} else {
item += ch;
}
code = code.substr(1);
}
Next();
}
function Throw(msg,dotl=true) {
if (dotl==true) {var tl=line-5;} else {var tl = 'unknown'};
if (tok==""||tok==""||msg.includes("OUT OF DATA")) {tl-=1;}
alert('🛑 ERROR: line '+tl+': '+msg);
throw 'line '+tl+': '+msg;
}
function Skip(t,eek) {
if (tok!=t && NoEekOnSkip==0) {
Throw(eek+': Expected "'+t+'" found "'+tok+'"');
}
Next();
}
function EndOfStatement() {
return tok==':'||tok=='';
}
function SkipEndOfStatement() {
if (!EndOfStatement()) {
Throw('Expected ":" (between statements) or "," (between parameters) or EOL');
}
Next();
}
function IsKeyword(a) {
var d = ''; if (inside_type == true) {d='(TYPE definition error)'}
if (':::keywords:::'.includes('.'+a.toLowerCase()+'.')){Throw(a+' is a reserved keyword '+d);}
}
function NewOp() {
ops.push(curop);
curop = '';
}
function If(e, n) {
if (n === undefined) {
n = [];
}
NewOp();
ops[ops.length - 1] += 'if (!(' + e + ')) { ip = ';
flow.push(['if', ops.length - 1, []]);
}
function Else() {
var f = flow.pop();
if (f[0] != 'if') {
Throw('ELSE unmatched to IF');
}
NewOp();
var pos = ops.length - 1;
ops[pos] += 'ip = ';
NewOp();
ops[f[1]] += ops.length + '; }\n';
flow.push(['else', null, f[2].concat(pos)]);
}
function ElseIf(e) {
var f = flow.pop();
if (f[0] != 'if') {
Throw('ELSEIF unmatched to IF');
}
NewOp();
var pos = ops.length - 1;
ops[pos] += 'ip = ';
NewOp();
ops[f[1]] += ops.length + '; }\n';
NewOp();
ops[ops.length - 1] += 'if (!(' + e + ')) { ip = ';
flow.push(['if', ops.length - 1, f[2].concat([pos])]);
}
function EndIf() {
NewOp();
var f = flow.pop();
if (f[0] == 'else') {
// nothing needed
} else if (f[0] == 'if') {
ops[f[1]] += ops.length + '; }\n';
} else {
Throw('Unmatch end if');
}
for (var i = 0; i < f[2].length; ++i) {
ops[f[2][i]] += ops.length + ';\n';
}
}
function VarPtr(vname) {
var vinfo;
if (vars[vname] !== undefined) {vinfo = vars[vname];}
else if (global_vars[vname] !== undefined) {vinfo = global_vars[vname];}
if (vinfo === undefined) {Throw('Undefined variable name');}
if (vinfo.global) {return vinfo.offset;}
else {return '(bp + ' + vinfo.offset + ')';}
}
function AddLabel(name) {
var n2=name.replace(/^0+/, "");
if (labels[n2]!==undefined) {Throw('Label '+n2+' defined twice');}
NewOp();
curop+='// LABEL '+n2+':\n';
labels[n2]=ops.length;
data_labels[n2]=data.length;
}
function Factor3() {
var ts=''; var te='';
if (tok=='('||tok=='['||tok=='{') {
if (tok=='[') {ts='[';te=']';}
else if (tok=='{') {ts='{';te='}';}
else {ts='(';te=')';}
Skip(ts);
var ret = Expression();
Skip(te);
return ret;
} else {
var name = tok;
Next();
if (name.substr(0, 1) == '"' ||
/^[0-9]*([.][0-9]*)?([eE][+-]?[0-9]+)?$/.test(name) ||
/^0x[0-9a-fA-F]+$/.test(name) ||
/^0b[0-9a-fA-F]+$/.test(name)) {
return name;
}
if (name == 'rnd') {
if (tok == '(') {
Skip('(');
if (tok != ')') {
var e = Expression();
}
Skip(')');
}
return 'Math.random()';
}
if (name == '_pi') {
var e = 1
if (tok == '(') {
Skip('(');
if (tok != ')') {
e = Expression();
}
Skip(')');
}
return 'Math.PI * ' + e;
}
if (name == 'varptr') {
Skip('(');
var vname = tok;
Next();
Skip(')');
return VarPtr(vname);
}
if (name == 'stackdepth') {
Skip('(');
Skip(')');
return 'sp';
}
if (name == 'basedepth') {
Skip('(');
Skip(')');
return 'bp';
}
if (name == 'true') {return '-1';}
if (name == 'false') {return '0';}
if (name=='_fontheight') {return 'font_height';}
if (name=='screen_aspect') {return 'screen_aspect';}
if (name=='_width') {return 'curr_width';}
if (name=='_height') {return 'curr_height';}
if (name=='xmax') {return 'curr_width - 1';}
if (name=='ymax') {return 'curr_height - 1';}
if (name=='_windowwidth') {return 'GetWinWidth()';}
if (name=='_windowheight') {return 'GetWinHeight()';}
if (name=='touchdevice') {return -+(('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) ||
(navigator.msMaxTouchPoints > 0));}
if (name=='csrlin') {return 'text_y + 1';}
if (name=='_mousex') {return 'mouse_x';}
if (name=='_mousey') {return 'mouse_y';}
if (name=='_mousebutton') {
if (tok=='(') {Skip('('); var e=Expression(); Skip(')');}
return 'mouse_buttons';}
if (name=='_mousewheel') {return 'MouseWheel()';}
if (name=='_audiodone') {return 'AudioDone()';}
if (name=='urlquerystring$') {return 'decodeURIComponent(window.location.search.substring(1))';}
if (name=='now$') {return 'Date().toString()';}
if (name=='time$') {return 'Date().toString().split(" ")[4]';}
if (name=='day$') {var t=new Date(); var r=['SUN','MON','TUE','WED','THU','FRI','SAT'][t.getDay()]; return '"' + r + '"';}
if (name=='date$') {
var today = new Date();
var dd = "0".concat(today.getDate().toString());
dd = dd.substr(dd.length-2, 2);
var mm = today.getMonth()+1;
mm = "0".concat(mm.toString());
mm = mm.substr(mm.length-2, 2);
var yyyy = today.getFullYear();
return '"".concat("' + mm + '","-","' + dd + '","-","' + yyyy + '")';
}
if (name=='log'||name=='ucase$'||name=='lcase$'||
name=='chr$'||name=='getchr$'||name=='sqr'||name=='hex$'||
name=='oct$'||name=='_bin$'||name=='bin$'||
name=='int'||name=='cint'||name=='cdbl'||name=='csng'||name=='fix'||name=='frac'||
name=='asc'||name=='fre'||name=='sgn'||
name=='abs'||name=='len'||name=='val'||
name=='cos'||name=='sin'||name=='tan'||name=='atn'||
name=='exp'||name=='_d2r'||name=='_r2d'||
name=='str$'||name=='peek'||name=='_red'||name=='_green'||name=='_blue'||
name=='ltrim$'||name=='rtrim$'||name=='spc'||
name=='space$'||name=='tab'||name=='pos'||name=='mapget'||
name=='confirm'||name=='getlocalstorageitem'||name=='getsessionstorageitem') {
Skip('(');
var e=Expression();
Skip(')');
if (name=='confirm') {curop+='Sleep(0.005);\n'; NewOp();}
switch (name) {
case 'log': return 'Math.log('+e+')';
case 'ucase$': return '('+e+').toUpperCase()'; case 'lcase$': return '('+e+').toLowerCase()';
case 'chr$': return 'String.fromCharCode('+e+')';
case 'getchr$': return 'GetChr('+e+')';
case 'asc': return '('+e+').charCodeAt(0)';
case 'fre': return '("60300")';
case 'sgn': return 'Math.sign('+e+')';
case 'sqr': return 'Math.sqrt('+e+')';
case 'hex$': return '(Math.round('+e+') >>> 0).toString(16)';
case 'oct$': return '(Math.round('+e+') >>> 0).toString(8)';
case 'bin$':
case '_bin$': return '(Math.round('+e+') >>> 0).toString(2)';
case 'int': return 'Math.floor('+e+')'; case 'cint': return 'Math.sign('+e+') * Math.round(Math.abs('+e+'))';
case 'cdbl': return 'Math.fround('+e+')'; case 'csng': return 'Math.fround('+e+')';
case 'fix': return 'Math.trunc('+e+')'; case 'abs': return 'Math.abs('+e+')';
case 'frac': return e + '- Math.trunc('+e+')';
case 'cos': return 'Math.cos('+e+')'; case 'sin': return 'Math.sin('+e+')';
case 'tan': return 'Math.tan('+e+')'; case 'atn': return 'Math.atan('+e+')';
case 'exp': return 'Math.exp('+e+')';
case '_d2r': return 'Number('+e+')*(Math.PI/180)'; case '_r2d': return 'Number('+e+')*(180/Math.PI)';
case 'str$': return 'ToString('+e+')';
case 'val': return '+('+e+')||0';
case 'peek': return 'Peek('+e+').toString()';
case '_red': return '('+e+'>>16)';
case '_green': return '('+e+'>>8)&0xFF';
case '_blue': return '('+e+'&0xFF)';
case 'len': return '(('+e+').length)';
case 'ltrim$': return '(('+e+').trimStart())';
case 'rtrim$': return '(('+e+').trimEnd())';
case 'spc': return 'StringRep(('+e+'), " ")';
case 'space$': return 'StringRep(('+e+'), " ")';
case 'tab': return 'StringRep((text_x < '+e+' ? '+e+'-text_x-1 : Math.floor(curr_width/8)-text_x-('+e+'<0?0:1)+'+e+'), " ")';
// case 'tab': return 'StringRep(('+e+'), "\t")';
case 'pos': return '(text_x+1)';
case 'confirm': return '-+confirm(('+e+'))';
case 'mapget': return 'MapGet('+e+')';
case 'getlocalstorageitem': return 'GetLocalStorageItem('+e+')';
case 'getsessionstorageitem': return 'GetSessionStorageItem('+e+')';
case 'stackdepth': return 'sp';
}
Throw('This cannot happen');
}
if (name=='instr') {
var i = '0';
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
if (tok==',') {
i=a; a=b;
Skip(',');
b = Expression();}
Skip(')');
return '(('+a+').indexOf('+b+','+i+'-1)+1)';
}
if (name=='atan2'||name=='_atan2'||name=='string$'||
name=='left$'||name=='right$'||name=='nvl$') {
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
Skip(')');
if (name=='atan2' || name=='_atan2') {return 'Math.atan2('+a+','+b+')';
} else if (name=='string$') {return 'StringRep('+a+','+b+')';
} else if (name=='left$') {return '(('+a+').substr(0,('+b+')))';
} else if (name=='right$') {return 'Right(('+a+'),('+b+'))';
} else if (name=='nvl$') {return a+'||'+b;
} else {throw 'impossible';
}
}
if (name=='prompt' || name=='_inputbox$') {
curop+='Sleep(0.005);\n'; NewOp();
Skip('(');
var a=Expression();
if (name=='_prompt' && tok==')') {
Skip(')');
var b='""';
}
else {
Skip(',');
if (name=='_inputbox$') {
a=Expression();
if (tok==')') {Skip(')'); var b='""'; }
else {Skip(','); var b=Expression(); Skip(')');}
}
else {
var b=Expression();
Skip(')');}
}
return 'prompt(('+a+'),('+b+'))';
}
if (name=='labelexists') {
Skip('('); var a=Expression(); Skip(')');
return 'LabelExists('+a+')';
}
if (name=='point') {
Skip('(');
var a=Expression();
if (tok==',') {Skip(',');var b=Expression();Skip(')');return 'Point(('+a+'), ('+b+'))';}
else {Skip(')');return 'PointPos('+a+')';}
}
if (name=='rgb2bgr') {
Skip('(');var a=Expression();Skip(')');return 'RGB2BGR('+a+')';}
if (name=='_rgb'||name=='_rgb32'||name=='bgr') {
Skip('('); var a=Expression();
Skip(','); var b=Expression();
Skip(','); var c=Expression(); Skip(')');
if (name=='bgr') {[a,c]=[c,a];return 'RGB2BGR(RGB2(' + a + ',' + b + ',' + c + '))';}
else {return 'RGB2(' + a + ',' + b + ',' + c + ')';}
}
if (name=='keystate') {
Skip('('); var a;
if (tok!=')') {a = Expression();} Skip(')');
return 'Keystate('+a+')';
}
if (name=='_mousezone') {
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
var c = '1'; var d = '1';
if (tok==',') {
Skip(','); c = Expression();
Skip(','); d = Expression();}
Skip(')');
return 'MouseZone ('+a+','+b+','+c+','+d+')';
}
if (name=='iff') {
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
Skip(',');
var c = Expression();
Skip(')');
return '('+ a + ' ? ' + b + ' : ' + c + ')';
}
if (name=='between') {
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
Skip(',');
var c = Expression();
var d = '0';
if (tok==',') {Skip(','); d = Expression();}
Skip(')');
return 'BETWEEN ('+a+','+b+','+c+','+d+')';
}
if (name=='min'||name=='max') {
// return 'Math.' + name + '(('+a+'),('+b+'))
var z = 'Math.' + name + '((';
Skip('(');
z = z + Expression();
while (tok==',') {
Skip(',');
z = z + '),(' + Expression();
}
Skip(')');
z = z + '))';
return '(' + z + ')';
}
if (name=='choose') {
Skip('(');
var a = Expression();
var z = '[';
while (tok==',') {
Skip(',');
z = z + Expression() + ',';
}
Skip(')');
z = z.slice(0,-1) + ']'
return '('+z+'['+a+'-1])';
}
if (name=='mid$' || name=='replace$') {
Skip('(');
var a = Expression();
Skip(',');
var b = Expression();
var c = "";
if (name == 'mid$') {
c = a + '.length + 1 -' + b;
};
if (tok == ',') {
Skip(',');
c = Expression();
}
Skip(')');
if (name == 'mid$') {
return '((' + a + ').substr((' + b + ') - 1, (' + c + ')))';
} else if (name == 'replace$') {
return 'StrReplace(' + a + ', ' + b + ', ' + c + ')';
}
}
if (name=='inkey$') {
return 'Inkey()';
}
if (name=='timer') {
return 'GetTimer()';
}
if (functions[name] !== undefined && !functions[name].is_subroutine) {
return FunctionCall(name, {is_subroutine: false});
}
return IndexVariable(name);
}
}
function Factor2() {
var a = Factor3();
while (tok == '^') {
Next();
var n = '';
if (tok=='-') {n=tok;Next();}
var b = Factor3();
a = 'Math.pow(' + a + ', ' + n + b + ')';
}
return a;
}
function Factor1() {
var ret = '';
while (tok == '+' || tok == '-') {
ret += tok;
Next();
}
return ret + '(' + Factor2() + ')';
}
function Factor() {
var a = Factor1();
while (tok == '*' || tok == '/'||tok == '\\'||tok == 'mod'||tok == 'div') {
var op = tok;
Next();
var b = Factor1();
if (op=='\\'||op=='div') {a = 'Math.floor((' + a + ')/(' + b + '))';}
else if (op=='mod') {a = '((' + a + ')%(' + b + '))';}
else {a = '(' + a + ')' + op + '(' + b + ')';}
}
return a;
}
function Term() {
var a = Factor();
while (tok == '+' || tok == '-') {
var op = tok;
Next();
var b = Factor();
a = '(' + a + ')' + op + '(' + b + ')';
}
return a;
}
function Relational() {
var a = Term();
while (tok == '=' || tok == '<' || tok == '>' ||
tok == '<>' || tok == '<=' || tok == '>=' || tok == '=>') {
var op = tok;
Next();
var op2 = op + tok;
if (op2 == '<>' || op2 == '<=' || op2 == '>=' || op2 == '=>') {
op = op2;
Next();
}
if (op == '=>') {
op = '>=';
}
var b = Term();
if (op == '=') {
a = '(' + a + ') == (' + b + ') ? -1 : 0';
} else if (op == '<>') {
a = '(' + a + ') != (' + b + ') ? -1 : 0';
} else {
a = '(' + a + ') ' + op + ' (' + b + ') ? -1 : 0';
}
}
return a;
}
function Logical1() {
var ret = '';
while (tok == 'not') {
Next();
ret += '~';
}
return ret + '(' + Relational() + ')';
}
function Logical() {
var a = Logical1();
while (tok == 'and') {
Next();
var b = Logical1();
a = '(' + a + ') & (' + b + ')';
}
return a;
}
function Logical03() {
var a = Logical();
while (tok == 'imp') {
Next();
var b = Logical();
a = '-Math.abs(+(!(' + a + '|' + b + ') | ' + b + '))';
}
return a;
}
function Logical02() {
var a = Logical03();
while (tok == 'eqv') {
Next();
var b = Logical03();
a = '-Math.abs(+(' + a + '==' + b + '))';
}
return a;
}
function Logical01() {
var a = Logical02();
while (tok == 'xor') {
Next();
var b = Logical02();
// a = '-Math.abs(+('+a+'? !'+b+':'+b+'))';
a = '('+a+')^('+b+')';
}
return a;
}
function Expression() {
var a = Logical01();
while (tok == 'or') {
Next();
var b = Logical01();
a = '(' + a + ') | (' + b + ')';
}
return a;
}
function TypeName() {
if (SIMPLE_TYPE_INFO[tok]) {
var type = tok;
Next();
return type;
} else if (tok == 'integer') {
Skip('integer');
return 'short';
} else if (tok == 'any') {
Skip('any');
// TODO: Handle this properly.
return 'string';
} else if (types[tok] !== undefined) {
var type_name = tok;
if (types[type_name] === undefined) {
Throw('Undefined type');
}
Next();
return type_name;
}
Throw('Undefined type "' + tok + '"');
}
function ImplicitType(name) {
return IMPLICIT_TYPE_MAP[name.slice(-3)] || IMPLICIT_TYPE_MAP[name.slice(-2)] || IMPLICIT_TYPE_MAP[name.slice(-1)] ||
letter_default[name[0]] || 'single';
}
function Align(alignment) {
allocated = Math.floor((allocated + alignment - 1) /
alignment) * alignment;
}
function Allocate(size) {
Align(size > 8 ? 8 : size);
var ret = allocated;
allocated += size;
return ret;
}
function DimScalarVariable(name, type_name, defaults) {
var info = types[type_name] || SIMPLE_TYPE_INFO[type_name];
if (info === undefined) {
Throw('Unknown type');
}
var size = info.size;
var offset = Allocate(size);
vars[name] = {
offset: offset,
dimensions: 0,
type_name: type_name,
global: vars === global_vars,
};
if (inside_type) {
var_decls += '// field ' + name + ' is at ' + offset + '\n';
} else if (vars[name].global) {
var_decls += '// ' + name + ' is at ' + offset + '\n';
} else {
if (inside_function) {
curop += '// ' + name + ' is at (bp + ' + offset + ')\n';
} else {
var_decls += '// ' + name + ' is at (bp + ' + offset + ')\n';
}
}
if (defaults.length > 0) {
curop += IndexVariable(name, true) + ' = ' + defaults[0] + ';\n';
}
}
function MaybeImplicitDimVariable(name, argument_to_function) {
// TODO: Handle array variables.
if (argument_to_function &&
argument_to_function.vars[name] !== undefined) {
return argument_to_function.vars[name];
}
if (vars[name] !== undefined) {
return vars[name];
}
if (global_vars[name] !== undefined) {
return global_vars[name];
}
if (option_explicit) {
Throw('Undeclared variable ' + name);
}
var type_name = ImplicitType(name);
DimScalarVariable(name, type_name, []);
return vars[name];
}
function ArrayPart(offset, i) {
return SIMPLE_TYPE_INFO['long'].view +
'[((' + offset + '>>2)+' + i + ')]';
}
function ReserveArrayCell(name) {
if (vars[name] === undefined &&
global_vars[name] == undefined) {
var offset = Allocate(4 + MAX_DIMENSIONS * 4 * 2);
vars[name] = {
offset: offset,
dimensions: null,
type_name: null,
global: vars === global_vars,
};
var boffset = offset;
if (!vars[name].global) {
boffset = '(bp+' + boffset + ')';
}
var_decls += '// ' + name + ' is at ' + ArrayPart(boffset, 0) +
' (cell-addr: ' + offset + ')\n';
}
if (vars[name] !== undefined) {
return vars[name];
}
return global_vars[name];
}
function DimVariable(default_tname,redim,is_declare) {
var name=tok;
IsKeyword(name);
Next();
// Pick default.
if (default_tname===null) {default_tname=ImplicitType(name);}
var type_name=default_tname;
var dimensions=[];
var defaults=[];
var is_scalar=true;
if (tok == '(') {
Skip('(');
if (tok==')') {Throw(name+' : missing dimension(s) for array?');}
is_scalar=false;
while (tok!=')') {
var e=Expression();
var d='dim'+const_count++;
//cjv var_decls+='const '+d+'=('+e+');\n';
curop+='const '+d+'=('+e+');\n'; //cjv
if (tok=='to') {
Skip('to');
var e1 = Expression();
var d1='dim'+const_count++;
//cjv var_decls += 'const ' + d1 + ' = (' + e1 + ');\n';
curop += 'const ' + d1 + ' = (' + e1 + ');\n'; //cjv
dimensions.push([d, d1]);
} else {
dimensions.push([option_base, d]);
}
if (tok != ',') {
break;
}
Skip(',');
}
Skip(')');
if (tok == '=') {
Skip('=');
Skip('{');
var e = Expression();
defaults.push(e);
while (tok == ',') {
Skip(',');
var e = Expression();
defaults.push(e);
}
Skip('}');
}
} else if (tok == '=') {
Skip('=');
var e = Expression();
defaults.push(e);
}
if (tok == 'as') {
Skip('as');
type_name = TypeName();
}
if (vars[name] !== undefined && vars[name].dimensions != null) {
if (redim) {
return;
}
Throw('Variable ' + name + ' defined twice');
}
if (is_scalar) {
DimScalarVariable(name, type_name, defaults);
} else {
if (dimensions.length > MAX_DIMENSIONS) {
Throw('Too many dimensions');
}
var offset = ReserveArrayCell(name).offset;
var info = types[type_name] || SIMPLE_TYPE_INFO[type_name];
var parts = [];
for (var i = 0; i < dimensions.length; i++) {
parts.push('((' + dimensions[i][1] + ')-(' +
dimensions[i][0] + ')+1)');
}
if (!is_declare) {
if (!vars[name].global) {
offset = '(bp+' + offset + ')';
}
curop += '// Allocate ' + name + '\n';
curop += 'if (' + ArrayPart(offset, 0) + ' === 0) {\n';
curop += ' ' + ArrayPart(offset, 0) + ' = Allocate(' +
[info.size].concat(parts).join('*') + ');\n';
for (var i = 0; i < dimensions.length; i++) {
curop += ' ' + ArrayPart(offset, i * 2 + 1) + ' = ' +
dimensions[i][0] + ';\n';
curop += ' ' + ArrayPart(offset, i * 2 + 2) + ' = ' +
[info.size].concat(parts).slice(0, i + 1).join('*') + ';\n';
}
if (defaults.length > 0) {
if (dimensions.length > 1) {
Throw('Only 1-d array defaults supported');
}
if (!SIMPLE_TYPE_INFO[type_name]) {
Throw('Only simple type array defaults supported');
}
for (var i = 0; i < defaults.length; i++) {
curop += ' ' + info.view + '[' +
' + (' + ArrayPart(offset, 0) + ' >> ' + info.shift + ') + '
+ i + '] = (' + defaults[i] + ');\n';
}
}
curop += '}\n';
}
vars[name] = {
offset: offset,
dimensions: dimensions.length > 0 ? dimensions.length : -1,
type_name: type_name,
global: vars === global_vars,
};
}
}
function IndexVariable(name, assignable, argument_to_function) {
IsKeyword(name);
var v = MaybeImplicitDimVariable(name, argument_to_function);
var offset = v.offset;
if (!v.global) {
if (argument_to_function) {
offset = '(sp+' + offset + ')';
} else {
if ((offset.toString()).indexOf('bp') == -1) {offset = '(bp+' + offset + ')';}
//cjv OFFSET BUG FIX ???
}
}
var type_name = v.type_name;
while (!argument_to_function && (tok == '(' || tok == '.')) {
if (tok=='(') {
Skip('(');
var dims=[];
var e='';
while (tok!=')') {
e=Expression();
dims.push(e);
if (tok!=',') {break;}
Skip(',');
}
if (e=='') {Throw(name+': undeclared function');}
Skip(')');
var info=types[type_name]||SIMPLE_TYPE_INFO[type_name];
// Extra indirection for array parameter access.
if (v.dimensions === -1) {
offset = 'i[' + offset + ']';
}
var noffset = '(';
noffset += ArrayPart(offset, 0) + ' + (';
if (v.dimensions !== -1 && dims.length != v.dimensions) {
if (v.dimensions==0) {
// Throw(name+': undeclared array/function');
Throw(name+': missing dimension or parameter');
}
else {
Throw('Array dimension expected ' + v.dimensions +
' but found ' + dims.length + ', array named: ' + name);
}
}
for (var i = 0; i < dims.length; ++i) {
noffset += '(((' + dims[i] + ')|0)-' +
ArrayPart(offset, i * 2 + 1) + ')';
noffset += '*' + ArrayPart(offset, i * 2 + 2);
if (i != dims.length - 1) {
noffset += '+';
}
}
noffset += '))';
offset = noffset;
} else if (tok == '.') {
Skip('.');
v = types[type_name];
if (v === undefined) {
Throw('Not a struct type');
}
var field = v.vars[tok];
if (field === undefined) {
Throw('Invalid field name');
}
Next();
offset = '(' + offset + ' + ' + field.offset + ')';
type_name = field.type_name;
}
}
var info = SIMPLE_TYPE_INFO[type_name];
if (!info) {
Throw('Expected simple type');
}
var vname = info.view + '[' + offset + '>>' + info.shift + ']';
if (info.view == 'str' && assignable === undefined) {
vname = '((' + vname + ')||"")';
}
return vname;
}
function FunctionDefine(options) {
var name = tok;
Next();
if (vars !== global_vars) {
Throw('Nested SUB/FUNCTION not allowed');
}
IsKeyword(name);
if (functions[name] !== undefined && !functions[name].is_declaration) {
Throw('SUB/FUNCTION/CONST/EQN already defined: ' + name);
}
NewOp();
var pos = ops.length - 1;
var parameters = [];
var old_allocated = allocated;
allocated = 0;
vars = {};
var nfunc = {
vars: vars,
parameters: parameters,
ip: ops.length,
allocation: -1,
is_subroutine: options.is_subroutine || false,
is_declaration: options.is_declaration || false,
};
if (nfunc.is_declaration) {
if (nfunc.is_subroutine) {
var_decls += '// SUB ' + name + '\n';
} else {
var_decls += '// FUNCTION ' + name + '\n';
}
} else {
if (nfunc.is_subroutine) {
curop += '// SUB ' + name + '\n';
} else {
curop += '// FUNCTION ' + name + '\n';
}
}
if (!nfunc.is_declaration) {
inside_function = true;
}
DimScalarVariable(name, ImplicitType(name), []);
// In case return value gets redefined.
Align(8);
if (tok == '(') {
Skip('(');
if (tok != ')') {
if (tok=='byref') {Skip(tok);}
if (tok=='byval') {Skip(tok);}
parameters.push(tok);
DimVariable(null, undefined, true);
while (tok == ',') {
Skip(',');
if (tok=='byref') {Skip(tok);}
if (tok=='byval') {Skip(tok);}
parameters.push(tok);
DimVariable(null, undefined, true);
}
}
Skip(')');
Align(8);
}
nfunc.allocation = allocated;
if (options.is_declaration) {
vars = global_vars;
allocated = old_allocated;
if (functions[name] == undefined) {
functions[name] = nfunc;
} else {
// TODO: Check for declaration mismatch in type.
if (functions[name].parameters.length != nfunc.parameter.length) {
Throw('DECLARE and definition parameters do not match');
}
}
} else {
function_old_allocated = old_allocated;
function_define_pos = pos;
function_name = name;
functions[name] = nfunc;
}
if (tok == 'as') {
Skip('as');
var type_name = TypeName();
if (!SIMPLE_TYPE_INFO[type_name]) {
Throw('Expected basic type');
}
functions[name].type_name = type_name;
}
if (tok == 'static') {
Skip('static');
// TODO: Implement.
}
}
function FunctionExit() {
if (vars === global_vars) {
Throw('SUB/FUNCTION EXIT only allowed inside SUB/FUNCTION.');
}
curop += 'sp -= 8; ip = i[sp>>2];\n';
NewOp();
}
function FunctionEnd() {
if (vars === global_vars) {
Throw('SUB/FUNCTION END only allowed at end of SUB/FUNCTION.');
}
inside_function = false;
FunctionExit();
ops[function_define_pos] += 'ip = ' + ops.length + ';\n';
vars = global_vars;
Align(8);
functions[function_name].allocation = allocated;
function_name = null;
allocated = function_old_allocated;
}
function FunctionCall(name,options) {
var func=functions[name];
if (func==undefined) {Throw(name+' is undeclared');}
if (options.is_subroutine!==func.is_subroutine) {
if (options.is_subroutine) {
Throw('Expected valid subroutine name, found: ' + name);
} else {
Throw('Expected valid function name, found: ' + name);
}
}
curop += 'i[sp>>2] = bp; sp += 8;\n';
var has_parens = tok == '(' || func.parameters.length != 0;
if ((options.is_call && has_parens) || (!options.is_subroutine && has_parens) || (!options.is_call && options.is_subroutine && has_parens)) {
Skip('(',name);
}
var args = [];
for (var i = 0; i < func.parameters.length; ++i) {
if (func.vars[func.parameters[i]].dimensions == -1) {
var vname = tok;
Next();
Skip('(');
Skip(')');
args.push(null);
curop += 'i[sp + ' + func.vars[func.parameters[i]].offset + '] = ' +
VarPtr(vname) + ';\n';
} else {
var old_tok_count = tok_count;
var old_tok = tok;
var e = Expression();
curop += IndexVariable(func.parameters[i], true, func) +
' = ' + e + ';\n';
if (vars[old_tok] && tok_count - old_tok_count == 1) {
args.push(old_tok);
} else {
args.push(null);
}
}
if (i != func.parameters.length - 1) {
Skip(',');
}
}
if ((options.is_call && has_parens) || (!options.is_subroutine && has_parens) || (!options.is_call && options.is_subroutine && has_parens)) {
Skip(')');
}
// Blank return value.
if (!options.is_subroutine) {
curop += IndexVariable(name, true, func) + ' = 123;\n';
}
curop += 'bp = sp;\n';
curop += 'sp += functions["' + name + '"].allocation;\n';
curop += 'i[sp>>2] = ip; sp += 8;\n';
curop += 'ip = functions["' + name + '"].ip;\n';
NewOp();
// TODO: Types?
curop += 'sp -= functions["' + name + '"].allocation;\n';
curop += 'bp = i[(sp-8)>>2];\n';
var temp = '#temp' + temp_count;
if (!options.is_subroutine) {
++temp_count;
DimScalarVariable(temp, func.vars[name].type_name, []);
curop += IndexVariable(temp, true) +
' = ' + IndexVariable(name, false, func) + ';\n';
}
for (var i = 0; i < args.length; ++i) {
if (args[i]) {
if (constants_list.indexOf('C'+args[i]+'C')>-1) {args[i] = '(' + args[i] + ')';}
curop += IndexVariable(args[i], true) + ' = ' +
IndexVariable(func.parameters[i], false, func) + ';\n';
}
}
curop += 'sp -= 8;\n';
if (!options.is_subroutine) {
return IndexVariable(temp, false);
}
}
function End() {
Sleep(0.5); yielding=1; autodisplay=1; quitting=1;
if (canvas) {
console.log('=== BASIC END ===');
setTimeout(function(){alert('=== END OF PROGRAM HAS BEEN REACHED ===')},10);
} else {
if (output_buffer!='') {
PutCh(null);
}
}
throw '';
}
function SetClipboardText(t) {
navigator.clipboard.writeText(t);
}
function fOpen(fname,fmode,fnum) {
localStorage.setItem('file'+fnum,'');
localStorage.setItem('file'+fnum+'_name',fname);
}
function fPrint(fnum, t, sttmnt) {
if (t.length==0) {
t = '\n';
}
else if (t.slice(-1)!==';' && t.slice(-1)!==',') {
t = t + '\n';
}
sessionStorage.setItem('file' + fnum, (sessionStorage.getItem('file' + fnum)) + t);
}
function fClose(fnum) {
hiddenElement.href = 'data:attachment/text,' + encodeURIComponent(localStorage.getItem('file' + fnum));
hiddenElement.target = '_blank';
hiddenElement.download = localStorage.getItem('file' + fnum + '_name') || 'BAM_' + fnum + '.txt';
hiddenElement.click();
}
function Lprint(t) {
spool_text=spool_text+t+'\n';
if (!spool_name) {
EndSpool();
}
}
function EndSpool() {
hiddenElement.href = 'data:attachment/text,' + encodeURIComponent(spool_text);
hiddenElement.target = '_blank';
hiddenElement.download = spool_name || 'BAM_LPRINT_Output.txt';
hiddenElement.click();
CancelSpool();
}
function CancelSpool() {
spool_name='';
spool_text='';
}
function OpenWindow(c) {
if ( window.location == window.parent.location ) {
var html = '';
openwindow = window.open('', 'ThisBamOutputWindow', '');
openwindow.document.write(html);
openwindow.document.body.innerHTML = c.replace('script',' script');
}}
function GetWinWidth() {return innerWidth;}
function GetWinHeight() {return innerHeight;}
function MapSet(k,v) {
gmap.set(k,v);
}
function MapGet(k) {
var v = gmap.get(k);
if (v===undefined) {v=""}
return v;
}
function ClearLocalStorage() {
localStorage.clear();
}
function RemoveLocalStorageItem(k) {
localStorage.removeItem(k);
}
function SetLocalStorageItem(k,v) {
localStorage.setItem(k,v);
}
function GetLocalStorageItem(k) {
var v = localStorage.getItem(k);
if (v === null) { v = ""}
return v;
}
function SetSessionStorageItem(k,v) {
sessionStorage.setItem(k,v);
}
function GetSessionStorageItem(k) {
var v = sessionStorage.getItem(k);
if (v === null) { v = ""}
return v;
}
function Sleep(t) {
yielding = 1;
delay = t * 1000;
}
function GetChr(k) {
var v = "";
var n=0;
var f = font_height;
for (let r=0;r<8;r++) {
for (let c=0;c<8;c++) {
n = font_data[k*64*f/8+r*8*f/8+c];
if (n==0) {v=v+'.';} else {v=v+'X';}
}
}
return v;
}
function LetChr(k,v) {
var f = font_height;
var n=0;
for (let r=0;r<8;r++) {
for (let c=0;c<8;c++) {
if (v[r*8+c]=='X') {n=255;} else {n=0;}
font_data[r*f + c +k*64*f/8]=n;
if (f==16) {font_data[(r)*f+8 + c +k*64*f/8]=n;}
}
}
}
function MouseWheel() {
var mwnow = mouse_wheel;
mouse_wheel = 0;
return mwnow;
}
function InitAudio() {globalAudioContext = new (window.AudioContext || window.webkitAudioContext)();}
function EndAudio() {yielding = 0; for (var i = 0; i < audio_queue.length; i++) { clearTimeout(audio_queue.pop());} audio_queue_timer = 0;}
function AudioDone() {return -(audio_queue_timer 0) {
return keys.shift();
} else {
return '';
}
}
function KeyClear() {
while (keys.length > 0) {Inkey();}
}
function Yield() {yielding=1;}
function Right(s,n) {return s.substr(s.length-n);}
function LabelExists(l) {
if (labels[((l).replace(/^0+/, "").toLowerCase())]!==undefined) {return -1;}
else {return 0;}
}
function BadLabel(l) {Throw("Invalid line identifier: "+l,false);}
function PointPos(f) {
if (f==0||f==2) {return pen_x;}
if (f==1||f==3) {return pen_y;}
}
function Point(x,y) {
x=Math.floor(x);
y=Math.floor(y);
var c=display_data[x+y*display.width];
if (color_map==undefined) {
return RGB2((c&0x000000ff),((c&0x0000ff00)>>8),((c&0x00ff0000)>>16));
}
if (color_map.length==16||color_map.length==256) {
return color_map.indexOf(c-0xff000000-0x1000000);
}
if (color_map.length==2) {
return color_map.indexOf(c);
}
if (color_map.length==4) {
if (c==0xff000000) {
return 0;
}
return color_map.indexOf(c-0xff000000-0x1000000);
}
return color_map;
}
function StringRep(n, ch) {
var ret = '';
var cch;
if (typeof ch == 'string') {
cch = ch;
} else {
cch = String.fromCharCode(ch);
}
for (var i = 0; i < n; ++i) {
ret += cch;
}
return ret;
}
function ToString(s) {
if (s < 0) {
return s.toString();
} else {
return ' ' + s.toString();
}
}
function StrReplace(str,replaceWhat,replaceTo) {
replaceWhat = replaceWhat.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
var re = new RegExp(replaceWhat, 'g');
return str.replace(re,replaceTo);
}
function Peek(addr) {
return 0;
}
function RGB(r, g, b) {
return BLACK | r | (g << 8) | (b << 16);
}
function RGB2(r,g,b) {
return +("0x" + ("0" + Math.floor(r).toString(16)).slice(-2) + ("0" + Math.floor(g).toString(16)).slice(-2) + ("0" + Math.floor(b).toString(16)).slice(-2));
}
function RGB2BGR(v) {
var cr = Math.floor(v/256/256);
var cg = Math.floor((v-cr*256*256)/256);
var cb = v-cr*256*256-cg*256;
return RGB(cr,cg,cb);
}
function MouseZone(x,y,w,h) {
if (mouse_x>=x && mouse_x<=(x+w-1) && mouse_y>=y && mouse_y<=(y+h-1))
{return -1;}
return 0;
}
function BETWEEN(a,b,c,d) {
if (d==0) {return ((ac)?0:-1));}
else {return ((a<=b)?0:((a>=c)?0:-1));}
}
function DefModes() {
// TODO: Handle color right in CGA, EGA, VGA modes.
var L=0x55,M=0xAA,H=0xFF;
var p2=[BLACK,WHITE];
var p4=[BLACK,RGB(0,M,M),RGB(M,0,M),RGB(M,M,M)];
var p16=[
RGB(0,0,0),RGB(0,0,M),RGB(0,M,0),RGB(0,M,M),RGB(M,0,0),RGB(M,0,M),RGB(M,L,0),RGB(M,M,M),
RGB(L,L,L),RGB(L,L,H),RGB(L,H,L),RGB(L,H,H),RGB(H,L,L),RGB(H,L,H),RGB(H,H,L),RGB(H,H,H)];
var p256=[
RGB(0,0,0),RGB(0,0,M),RGB(0,M,0),RGB(0,M,M),RGB(M,0,0),RGB(M,0,M),RGB(M,M,0),RGB(M,M,M),
RGB(0,0,L),RGB(0,0,H),RGB(0,M,L),RGB(0,M,H),RGB(M,0,L),RGB(M,0,H),RGB(M,M,L),RGB(M,M,H),
RGB(0,L,0),RGB(0,L,M),RGB(0,H,0),RGB(0,H,M),RGB(M,L,0),RGB(M,L,M),RGB(M,H,0),RGB(M,H,M),
RGB(0,L,L),RGB(0,L,H),RGB(0,H,L),RGB(0,H,H),RGB(M,L,L),RGB(M,L,H),RGB(M,H,L),RGB(M,H,H),
RGB(L,0,0),RGB(L,0,M),RGB(L,M,0),RGB(L,M,M),RGB(H,0,0),RGB(H,0,M),RGB(H,M,0),RGB(H,M,M),
RGB(L,0,L),RGB(L,0,H),RGB(L,M,L),RGB(L,M,H),RGB(H,0,L),RGB(H,0,H),RGB(H,M,L),RGB(H,M,H),
RGB(L,L,0),RGB(L,L,M),RGB(L,H,0),RGB(L,H,M),RGB(H,L,0),RGB(H,L,M),RGB(H,H,0),RGB(H,H,M),
RGB(L,L,L),RGB(L,L,H),RGB(L,H,L),RGB(L,H,H),RGB(H,L,L),RGB(H,L,H),RGB(H,H,L),RGB(H,H,H),
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,RGB(H,H,H)];
return {
0: [640,200,2.4,8,p16,4], 1: [320,200,1.2,8,p4,2],
2: [640,200,2.4,8,p2,1], 7: [320,200,1.2,8,p16,4],
8: [640,200,2.4,8,p16,4], 9: [640,350,480/350,14,p16,4],
10: [640,350,480/350,14,p2,1], 11: [640,480,1,16,p2,1],
12: [640,480,1,16,p16,4], 13: [320,200,1.2,8,p256,8],
14: [320,200,1,8,p256,8], 15: [320,200,2.4,8,p256,8],
16: [320,200,1.2,16,p256,8], 17: [320,200,1,16,p256,8],
23: [640,400,1.2,8,undefined,24],
24: [640,400,1,8,undefined,24], 25: [640,400,2.4,8,undefined,24],
26: [640,400,1.2,16,undefined,24], 27: [640,400,1,16,undefined,24]
}
}
function InitPalette() {
var modes=DefModes();
var m=modes[screen_mode];
color_map=m[4];
// reverse_color_map = {};
if (color_map !== undefined) {
for (var i = 0; i < color_map.length; ++i) {
reverse_color_map[color_map[i]] = i;
}
fg_color = color_map[color_map.length - 1];
bg_color = color_map[0];
} else {
fg_color = WHITE;
bg_color = BLACK;
}
}
function Screen(mode, m0, m1) {
if (mode==32) {mode=27;}
else if ( [0,1,2,7,8,9,10,11,12,13,14,15,16,17,23,24,25,26,27].indexOf(mode) == -1) {
mode = 0;
curr_mode= 0;
}
else {curr_mode = mode;}
if (!canvas) {return;}
// TODO: Handle color right in CGA, EGA, VGA modes.
// var monochrome=DefPal(2);
// cjv: adding 16 colors to rgba for gw-basic compatibility was a bad idea; reverted
// var p16=DefPal(16);
// var p256=DefPal(256);
// var screen1=DefPal(4);
var modes=DefModes();
var m=modes[mode];
if (m===undefined) {
Throw('Invalid mode '+mode);
}
if (m0!=undefined) {
m[0]=m0;
}
if (m1!=undefined) {
m[1]=m1;
}
curr_width=m[0];
curr_height=m[1];
SetupDisplay(m[0],m[1],m[2],m[3]);
window.dispatchEvent(new Event('resize'));
color_map=m[4];
screen_bpp=m[5];
reverse_color_map = {};
if (color_map !== undefined) {
for (var i = 0; i < color_map.length; ++i) {
reverse_color_map[color_map[i]] = i;
}
fg_color = color_map[color_map.length - 1];
bg_color = color_map[0];
} else {
fg_color = WHITE;
bg_color = BLACK;
}
screen_mode = mode;
pen_x = display.width / 2;
pen_y = display.height / 2;
Cls(0);
}
function Width(w) {
//if (screen_mode == 0 && (w == 80 || w == 40)) {
// SetupDisplay(w * 8, display.height, w == 80 ? 2.4 : 1.2, font_height);
//}
var modes=DefModes();
var m=modes[screen_mode];
if (m[0] > 0) {
SetupDisplay(w * 8, display.height, ( w * m[2] / (m[0]/8) ), font_height);
Cls(0);}
}
function Height(w) {
var modes=DefModes();
var m=modes[screen_mode];
if (m[0] > 0) {
var ny = w * m[3];
var nx = display.width * (ny/display.height);
SetupDisplay(display.width, ny, ( nx * m[2] / (m[0]/font_height) ), font_height);
Cls(0);}
}
var output_buffer = '';
function PutCh(ch) {
if (!canvas) {
if (ch == null) {
console.log(output_buffer);
output_buffer = '';
} else {
output_buffer += ch;
}
return;
}
if (ch == null) {
text_x = 0;
text_y++;
}
else {
var fg = fg_color;
var bg = bg_color;
var chcode = (ch.charCodeAt(0) & 0xff) >>> 0;
var chpos = chcode * font_height * 8;
for (var y = 0; y < font_height; ++y) {
var pos = text_x * 8 + (y + text_y * font_height) * display.width;
for (var x = 0; x < 8; ++x) {
display_data[pos++] = font_data[chpos++] ? fg : bg;
}
}
text_x++;
if (text_x >= text_width) {
text_y++;
text_x = 0;
}
}
if (text_y >= text_height) {
text_y = text_height - 1;
for (var i = (font_height*display.width - 1); i < (display.width * display.height - 1); i++) {
display_data[i-(font_height*display.width)] = display_data[i];
}
for (var i = ((display.width*display.height)-(font_height*display.width)); i < (display.width * display.height - 1); i++) {
display_data[i] = bg_color;
}
}
}
function Pcopy(x1,y1,x2,y2,s,d) {
var srcdata;
if (x1==undefined || x1<0) {x1=0;}
if (y1==undefined || y1<0) {y1=0;}
if (x2==undefined || Math.floor(x2)>display.width-1) {x2=display.width-1;}
if (y2==undefined || Math.floor(y2)>display.height-1) {y2=display.height-1;}
x1=Math.floor(x1);y1=Math.floor(y1);
x2=Math.floor(x2);y2=Math.floor(y2);
switch(s) {
case -1:
srcdata = page0; break;
case 0:
srcdata = display_data; break;
case 1:
if (page1==undefined) {alert("Page 1 is undefined");}
srcdata = page1; break;
case 2:
if (page2==undefined) {alert("Page 2 is undefined");}
srcdata = page2; break;
default:
alert(s + " is an invalid source page for PCOPY."); return;
}
switch(d) {
case -1:
page0=[...srcdata];
break;
case 0:
if (x1==0 && y1==0 && x2==display.width-1 && y2==display.height - 1) {
for (var i = 0; i < display.width * display.height; i++) {
display_data[i] = srcdata[i];}}
else {for (var y = y1; y < y2+1; y++) {
for (var x = x1; x < x2+1; x++) {
display_data[x+y*display.width] = srcdata[x+y*display.width];
}}}
break;
case 1:
if (page1==undefined) {page1=[...srcdata];}
else if (x1==0 && y1==0 && x2==display.width-1 && y2==display.height - 1) {page1=[...srcdata];}
else {for (var y = y1; y < y2+1; y++) {
for (var x = x1; x < x2+1; x++) {
page1[x+y*display.width] = srcdata[x+y*display.width];
}}}
break;
case 2:
if (page2==undefined) {page2=[...srcdata];}
else if (x1==0 && y1==0 && x2==display.width-1 && y2==display.height - 1) {page2=[...srcdata];}
else {for (var y = y1; y < y2+1; y++) {
for (var x = x1; x < x2+1; x++) {
page2[x+y*display.width] = srcdata[x+y*display.width];
}}}
break;
default:
alert(d + " is an invalid destination page for PCOPY."); return;
}
}
function Scroll(x1,y1,x2,y2,h,v,w) {
var tempdata;tempdata = [...display_data];
var wx=0; var wy=0;
if (x1==undefined || x1<0) {x1=0;}
if (y1==undefined || y1<0) {y1=0;}
if (x2==undefined || x2>display.width-1) {x2=display.width-1;}
if (y2==undefined || y2>display.height-1) {y2=display.height-1;}
x1=Math.floor(x1); y1=Math.floor(y1); x2=Math.floor(x2); y2=Math.floor(y2); h=Math.floor(h);v=Math.floor(v);
h=h%(x2-x1);v=v%(y2-y1);
var xMin = x1; var xMax = x2; var yMin = y1; var yMax = y2;
if (h<0) {xMax += h;} else {xMin += h;}
if (v<0) {yMax += v; } else {yMin += v;}
// alert('xMin: ' + xMin + 'xMax: ' + xMax + 'yMin: ' + yMin + 'yMax: ' + yMax + '\ndisplay.width:' + display.width + 'display.height:' + display.height);
for (var y = y1; y < y2+1; y++) {
for (var x = x1; x < x2+1; x++) {
if (y>=yMin && y<=yMax && x>=xMin && x<=xMax) {
display_data[x + y * display.width] = tempdata[x + y * display.width - h - v*display.width];}
else {
if (w==0) {display_data[x + y * display.width] = bg_color;}
else {
if (xxMax) {wx=xMin+(x-xMax)-1;} else {wx=x-h;}
if (yyMax) {wy=yMin+(y-yMax)-1;} else {wy=y-v;}
display_data[x + y * display.width] = tempdata[wx + wy * display.width];}
}
}
}
}
function LineInput(crlf=1) {
while (keys.length > 0) {
const key = keys.shift();
if (key == String.fromCharCode(13)) {
--text_x;
if (crlf==1) {PutCh(' ');PutCh(null);}
return;
}
if (key == String.fromCharCode(8) && input_string.length > 0) {
input_string = input_string.substr(0, input_string.length - 1);
--text_x;
PutCh(' ');
text_x -= 2;
PutCh(String.fromCharCode(219));
}
if (key.charCodeAt(0) >= 32 && key.charCodeAt(0) <= 126) {
--text_x;
PutCh(key);
PutCh(String.fromCharCode(219));
input_string += key;
}
}
yielding = 1;
--ip;
}
function Print(items, sttmnt='p', fnum=null) {
if (items.length==0) {
PutCh(null);
return;
}
for (var i=0;i 0 ? 1 : 0);
value = Math.abs(value);
var before = 0;
var after = 0;
var found_point = false;
for (var i = 0; i < format.length; ++i) {
if (format[i] == '.') {
found_point = true;
} else if (format[i] == '#') {
if (found_point) {
++after;
} else {
++before;
}
}
}
var t = value;
var fail = Math.floor(t * Math.pow(10, -before)) > 0;
value = value * Math.pow(10, after);
var ret = '';
var done = false;
for (var i = format.length - 1; i >= 0; --i) {
if (format[i] == '#') {
if (fail) {
ret = '*' + ret;
} else if (done) {
ret = ' ' + ret;
} else {
ret = Math.floor(value % 10) + ret;
value = Math.floor(value / 10);
if (value == 0) {
done = true;
}
}
} else if (format[i] == '+' || format[i] == '-') {
if (fail) {
ret = '*' + ret;
} else if (sgn < 0) {
ret = '-' + ret;
} else if (sgn > 0) {
if (format[i] == '+') {
ret = '+' + ret;
}
} else {
ret = ' ' + ret;
}
} else if (format[i] == ',') {
if (fail) {
ret = '*' + ret;
} else if (done) {
ret = ' ' + ret;
} else {
ret = ',' + ret;
}
} else {
ret = format[i] + ret;
}
}
return ret;
}
function PrintUsing(format, items) {
var parts = [];
var p = '';
var has_num = false;
for (var i = 0; i < format.length; ++i) {
if (format[i] == '#' || format[i] == ',' || format[i] == '.') {
has_num = true;
} else {
if (has_num) {
parts.push(p)
p = '';
has_num = false;
}
}
p += format[i];
}
if (p != '') {
if (has_num) {
parts.push(p);
} else {
parts[parts.length - 1] += p;
}
}
var values = [];
for (var i = 0; i < items.length; i += 2) {
if (parts.length * 2 > i) {
items[i] = Using(parts[(i / 2) | 0], items[i]);
}
}
Print(items);
}
function ColorFlip(c) {
return BLACK |
((c & 0xff0000) >> 16) | ((c & 0xff) << 16) | (c & 0x00ff00);
}
function FixupColor(c) {
if (c === undefined) {c=fg_id;}
if (c === undefined) {
if (color_map ) {
return color_map[color_map.length - 1];
} else {
return WHITE;
}
}
if (color_map !== undefined) {
// cjv: gw-basic compatibility hack
var cml = color_map.length;
c = ((c % cml ) + cml) % cml;
return color_map[(c%color_map.length)] || color_map[color_map.length - 1]; // cjv || BLACK;
} else {
c = c | 0;return ColorFlip(c);
}
}
function Palette(c, v) {if (c < color_map.length) {color_map[c] = v;reverse_color_map[color_map[c]] = c;}}
function Color(fg, bg) {
if (fg != undefined) {fg_color = FixupColor(fg);fg_id=fg;};
if (bg != undefined) {bg_color = FixupColor(bg);bg_id=bg;};
}
// function Color_old(fg, bg) {
// if (screen_mode == 0 || screen_mode > 2) {
// if (fg != undefined) fg_color = FixupColor(fg);
// } else {
// fg_color = FixupColor(undefined);
// }
// if (screen_mode == 0 || screen_mode > 2) {
// if (bg != undefined) bg_color = FixupColor(bg);
// } else {
// bg_color = FixupColor(undefined);
// }
// }
function Locate(x, y) {
if (x != 0) { text_x = x - 1;}
if (y != 0) {text_y = y - 1;}
// Hack to yield more often (for NIBBLES.BAS)
if (x == 1 && y == 1) {
yielding = 1;
}
}
function Box(x1, y1, x2, y2, c) {
x1 = x1 | 0;
y1 = y1 | 0;
x2 = x2 | 0;
y2 = y2 | 0;
c = c | 0;
if (x1 > x2) {
var t = x2;
x2 = x1;
x1 = t;
}
if (y1 > y2) {
var t = y2;
y2 = y1;
y1 = t;
}
if (x1 >= display.width ||
y1 >= display.height ||
x2 < 0 || y2 < 0) {
return;
}
if (x1 < 0) x1 = 0;
if (x2 > display.width - 1) x2 = display.width - 1;
if (y1 < 0) y1 = 0;
if (y2 > display.height - 1) y2 = display.height - 1;
for (var y = y1; y <= y2; ++y) {
var pos = x1 + y * display.width;
for (var x = x1; x <= x2; ++x) {
display_data[pos++] = c;
}
}
}
function RawLine(x1, y1, x2, y2, c) {
x1 = x1 | 0;
y1 = y1 | 0;
x2 = x2 | 0;
y2 = y2 | 0;
if (x1 == x2 || y1 == y2) {
Box(x1, y1, x2, y2, c);
return;
}
if (Math.abs(x1 - x2) > Math.abs(y1 - y2)) {
if (x1 > x2) {
var tmp;
tmp = x1; x1 = x2; x2 = tmp;
tmp = y1; y1 = y2; y2 = tmp;
}
for (var x = x1; x <= x2; ++x) {
var t = (x - x1) / (x2 - x1);
// cjv: changed from Math.floor to Math.round; keep an eye on this
var y = y1 + Math.round(t * (y2 - y1));
Box(x, y, x, y, c);
}
} else {
if (y1 > y2) {
var tmp;
tmp = x1; x1 = x2; x2 = tmp;
tmp = y1; y1 = y2; y2 = tmp;
}
for (var y = y1; y <= y2; ++y) {
var t = (y - y1) / (y2 - y1);
// cjv: changed from Math.floor to Math.round; keep an eye on this
var x = x1 + Math.round(t * (x2 - x1));
Box(x, y, x, y, c);
}
}
}
function Line(x1, y1, x2, y2, c, fill) {
var pen_color = FixupColor(c);
if (fill == 0) {
// Should be line.
RawLine(x1, y1, x2, y2, pen_color);
} else if (fill == 1) {
Box(x1, y1, x2, y1, pen_color);
Box(x1, y2, x2, y2, pen_color);
Box(x1, y1, x1, y2, pen_color);
Box(x2, y1, x2, y2, pen_color);
} else {
Box(x1, y1, x2, y2, pen_color);
}
}
var last = 0;
function Line2(x1, y1, x2, y2, c, fill) {
var pen_color = FixupColor(c);
if (fill == 0) {
// Should be line.
RawLine(x1, y1, x2, y2, pen_color);
} else if (fill == 1) {
Box(x1, y1, x2, y1, pen_color);
Box(x1, y2, x2, y2, pen_color);
Box(x1, y1, x1, y2, pen_color);
Box(x2, y1, x2, y2, pen_color);
} else {
Box(x1, y1, x2, y2, pen_color);
}
pen_x = x2;
pen_y = y2;
}
var last = 0;
function Cls(mode) {
// TODO: Handle mode.
Box(0, 0, display.width, display.height, bg_color);
text_x = 0;
text_y = 0;
}
function Pset(x, y, c) {
x = Math.floor(x);
y = Math.floor(y);
if (x<0 || y<0 || x>=display.width || y>=display.height) {}
else {
var pen_color = FixupColor(c);
if (c==-1) {pen_color=bg_color;}
else if (c==-2) {pen_color=fg_color;}
display_data[x + y * display.width] = pen_color;
pen_x = x;
pen_y = y;
}
}
function Pset2(x, y, c) {
x = Math.floor(x);
y = Math.floor(y);
if (x<0 || y<0 || x>=display.width || y>=display.height) {}
else {
display_data[x + y * display.width] = c;
}}
function Circle(x, y, r, c, start, end, aspect, fill) {
x=Math.floor(x);
y=Math.floor(y);
r=Math.floor(r);
var pen_color = FixupColor(c);
if (c==-1) {pen_color=bg_color;}
else if (c==-2) {pen_color=fg_color;}
var complete = false;
if (start < 0) { start = -start; complete = true; }
if (end < 0) { end = -end; complete = true; }
if (end < start) {
end += Math.PI * 3;
}
var rx, ry;
if (aspect == null) {
rx = r;
ry = r / screen_aspect;
} else if (aspect > 1) {
rx = r / aspect;
ry = r;
} else {
rx = r;
ry = r * aspect;
}
if (start != 0 || (end != Math.PI * 3) || aspect != null) {
x += 0.5;
y += 0.5;
var oxx = x + Math.cos(start) * rx;
var oyy = y - Math.sin(start) * ry;
if (complete) {
RawLine(x, y, oxx, oyy, pen_color);
}
for (var ang = start; ang <= end; ang += 0.03) {
var xx = x + Math.cos(ang) * rx;
var yy = y - Math.sin(ang) * ry;
if (ang == start) { oxx = xx; oyy = yy; }
RawLine(oxx, oyy, xx, yy, pen_color);
oxx = xx;
oyy = yy;
}
if (complete) {
RawLine(x, y, xx, yy, pen_color);
}
}
else {
var a;
function DoPset2(x,xy,a,y,asa,xysa) {
Pset2(x+xy,y-asa, pen_color);
Pset2(x-xy,y-asa, pen_color);
Pset2(x+xy,y+asa, pen_color);
Pset2(x-xy,y+asa, pen_color);
Pset2(x-a,y+xysa, pen_color);
Pset2(x-a,y-xysa, pen_color);
Pset2(x+a,y+xysa, pen_color);
Pset2(x+a,y-xysa, pen_color);
if (fill==2) {
Pset2(x+xy-1,y-asa, pen_color);
Pset2(x-xy+1,y-asa, pen_color);
Pset2(x+xy-1,y+asa, pen_color);
Pset2(x-xy+1,y+asa, pen_color);
Pset2(x-a+1,y+xysa, pen_color);
Pset2(x-a+1,y-xysa, pen_color);
Pset2(x+a-1,y+xysa, pen_color);
Pset2(x+a-1,y-xysa, pen_color);
Pset2(x+xy,y-asa+1, pen_color);
Pset2(x-xy,y-asa+1, pen_color);
Pset2(x+xy,y+asa-1, pen_color);
Pset2(x-xy,y+asa-1, pen_color);
Pset2(x-a,y+xysa-1, pen_color);
Pset2(x-a,y-xysa+1, pen_color);
Pset2(x+a,y+xysa-1, pen_color);
Pset2(x+a,y-xysa+1, pen_color);}
}
for (var xy = 0; xy < r*0.8; xy += 1) {
a = Math.round(Math.sqrt(r * r - xy * xy));
// DoPset2(x,xy,a,y,(a),xy);
DoPset2(x,xy,a,y,(a/screen_aspect),xy/screen_aspect);
}
}
if (fill==1 && start == 0 && end > Math.PI * 2) {
Paint(x, y, c, c);
}
pen_x = x;
pen_y = y;
}
function Circle_OLD(x, y, r, c, start, end, aspect, fill) {
x=Math.floor(x);
y=Math.floor(y);
r=Math.floor(r);
var pen_color = FixupColor(c);
var complete = false;
if (start < 0) { start = -start; complete = true; }
if (end < 0) { end = -end; complete = true; }
if (end < start) {
end += Math.PI * 3;
}
var rx, ry;
if (aspect == null) {
rx = r;
ry = r / screen_aspect;
} else if (aspect > 1) {
rx = r / aspect;
ry = r;
} else {
rx = r;
ry = r * aspect;
}
if (start != 0 || (end != Math.PI * 3) || aspect != null) {
x += 0.5;
y += 0.5;
var oxx = x + Math.cos(start) * rx;
var oyy = y - Math.sin(start) * ry;
if (complete) {
RawLine(x, y, oxx, oyy, pen_color);
}
for (var ang = start; ang <= end; ang += 0.03) {
var xx = x + Math.cos(ang) * rx;
var yy = y - Math.sin(ang) * ry;
if (ang == start) { oxx = xx; oyy = yy; }
RawLine(oxx, oyy, xx, yy, pen_color);
oxx = xx;
oyy = yy;
}
if (complete) {
RawLine(x, y, xx, yy, pen_color);
}
}
else {
var a; var a_ar; var xy_ar;
for (var xy = 0; xy < r*0.8; xy += 1) {
a = Math.round(Math.sqrt(r * r - xy * xy));
Pset(x+xy,y-(a/screen_aspect), c);
Pset(x-xy,y-(a/screen_aspect), c);
Pset(x+xy,y+(a/screen_aspect), c);
Pset(x-xy,y+(a/screen_aspect), c);
Pset(x-a,y+(xy/screen_aspect), c);
Pset(x-a,y-(xy/screen_aspect), c);
Pset(x+a,y+(xy/screen_aspect), c);
Pset(x+a,y-(xy/screen_aspect), c);
Pset(x+xy-1,y-(a/screen_aspect), c);
Pset(x-xy+1,y-(a/screen_aspect), c);
Pset(x+xy-1,y+(a/screen_aspect), c);
Pset(x-xy+1,y+(a/screen_aspect), c);
Pset(x-a+1,y+(xy/screen_aspect), c);
Pset(x-a+1,y-(xy/screen_aspect), c);
Pset(x+a-1,y+(xy/screen_aspect), c);
Pset(x+a-1,y-(xy/screen_aspect), c);
Pset(x+xy,y-(a/screen_aspect)+1, c);
Pset(x-xy,y-(a/screen_aspect)+1, c);
Pset(x+xy,y+(a/screen_aspect)-1, c);
Pset(x-xy,y+(a/screen_aspect)-1, c);
Pset(x-a,y+(xy/screen_aspect)-1, c);
Pset(x-a,y-(xy/screen_aspect)+1, c);
Pset(x+a,y+(xy/screen_aspect)-1, c);
Pset(x+a,y-(xy/screen_aspect)+1, c);
}
}
if (fill && start == 0 && end > Math.PI * 2) {
Paint(x, y, c, c);
}
pen_x = x;
pen_y = y;
}
function GetImage(x1, y1, x2, y2, buffer, offset) {
x1 = x1 | 0;
y1 = y1 | 0;
x2 = x2 | 0;
y2 = y2 | 0;
if (x1>x2) {[x1,x2]=[x2,x1];}
if (y1>y2) {[y1,y2]=[y2,y1];}
var d16 = new Uint16Array(buffer);
if (screen_bpp <= 2) {
d16[(offset >> 1) + 0] = (x2 - x1 + 1) * screen_bpp;
} else {
d16[(offset >> 1) + 0] = (x2 - x1 + 1);
}
d16[(offset >> 1) + 1] = y2 - y1 + 1;
var d = new Uint8Array(buffer);
var src = display_data;
if (screen_bpp > 8) {
var dstpos = offset + 4;
for (var y = y1; y <= y2; ++y) {
var srcpos = x1 + y * display.width;
for (var x = x1; x <= x2; ++x) {
var v = src[srcpos++];
d[dstpos++] = v;
d[dstpos++] = (v >> 8);
d[dstpos++] = (v >> 16);
}
}
} else {
var dstpos = offset + 4;
var shift = 8;
var v = 0;
for (var y = y1; y <= y2; ++y) {
var srcpos = x1 + y * display.width;
for (var x = x1; x <= x2; ++x) {
shift -= screen_bpp;
var cc = reverse_color_map[src[srcpos++] | BLACK] | 0;
v |= (cc << shift);
if (shift == 0) {
d[dstpos++] = v;
v = 0;
shift = 8;
}
}
if (shift != 8) {
d[dstpos++] = v;
v = 0;
shift = 8;
}
}
}
}
function PutImage(x1, y1, buffer, offset, mode) {
x1 = x1 | 0;
y1 = y1 | 0;
var s16 = new Uint16Array(buffer);
var x2;
if (screen_bpp <= 2) {
x2 = x1 + (s16[(offset >> 1) + 0] / screen_bpp) - 1;
} else {
x2 = x1 + s16[(offset >> 1)] - 1;
}
var y2 = y1 + s16[(offset >> 1) + 1] - 1;
var s = new Uint8Array(buffer);
var dst = display_data;
if (screen_bpp > 8) {
var srcpos = offset + 4;
for (var y = y1; y <= y2; ++y) {
var dstpos = x1 + y * display.width;
for (var x = x1; x <= x2; ++x) {
var v = s[srcpos] | (s[srcpos + 1] << 8) | (s[srcpos + 2] << 16);
srcpos += 3;
// TODO: Optimize
if (x < 0 || x >= display.width || y < 0 || y >= display.height) {
dstpos++;
continue;
}
if (mode == 'xor') {
dst[dstpos++] = (dst[dstpos] ^ v) | BLACK;
} else if (mode == 'preset') {
dst[dstpos++] = (~v) | BLACK;
} else if (mode == 'and') {
dst[dstpos++] = (dst[dstpos] & v) | BLACK;
} else if (mode == 'or') {
dst[dstpos++] = (dst[dstpos] | v) | BLACK;
} else {
dst[dstpos++] = v | BLACK;
}
}
}
} else {
var srcpos = offset + 4;
var mask = (1 << screen_bpp) - 1;
for (var y = y1; y <= y2; ++y) {
var dstpos = x1 + y * display.width;
var v = 0;
var shift = 8;
for (var x = x1; x <= x2; ++x) {
if (shift == 8) {
v = s[srcpos++];
}
shift -= screen_bpp;
var cc = (v >> shift) & mask;
var old = reverse_color_map[dst[dstpos] | BLACK] | 0;
if (mode == 'xor') {
cc ^= old;
} else if (mode == 'preset') {
cc = cc ^ mask;
} else if (mode == 'and') {
cc &= old;
} else if (mode == 'or') {
cc |= old;
}
// alert('color_map[cc]: ' + color_map[cc]);
var px = color_map[cc] | 0;
// TODO: Optimize
if (y >= 0 && y < display.height && x >= 0 && x < display.width) {
dst[dstpos++] = px;
} else {
dstpos++;
}
if (shift == 0) {
shift = 8;
}
}
}
}
}
var draw_state = {
noplot: false,
nomove: false,
angle: 0,
turn_angle: 0,
color: undefined,
scale: 1,
};
function StepUnscaled(dx, dy) {
if (!draw_state.noplot) {
Line(pen_x, pen_y, pen_x + dx, pen_y + dy, draw_state.color, 0);
}
if (!draw_state.nomove) {
pen_x += dx;
pen_y += dy;
}
draw_state.noplot = false;
draw_state.nomove = false;
}
function Step(dx, dy) {
StepUnscaled(dx * draw_state.scale, dy * draw_state.scale);
}
function Draw(cmds) {
function AngleStep(a_inc) {
var a_tot = draw_angle*Math.PI/180+a_inc*Math.PI/180;
Step(Math.round(Math.cos(a_tot)*n),Math.round(-Math.sin(a_tot)*n));
}
cmds = cmds.toLowerCase();
cmds = cmds.replace(/\s+/g, '');
cmds = cmds.replace(/;/g, '');
cmds = cmds.replace(/=/g, '');
var m;
while (cmds.length) {
if (m = cmds.match(/^(u|d|l|r|e|f|g|h|w|x|y|z|a|ta|c|s)([0-9.+-]+)?/)) {
var op = m[1];
var n = m[2] == '' ? 1 : m[2];
if (op == 'c') {
draw_state.color = n;
} else if (op=='a') {
draw_angle=n*90;
} else if (op=='ta') {
draw_angle=n;
} else if (op=='s') {
draw_state.scale = n / 4;
} else if (op=='u') {AngleStep(90);}
else if (op=='d') {AngleStep(270);}
else if (op=='l') {AngleStep(180);}
else if (op=='r') {AngleStep(0);}
else if (op=='e') {n=Math.sqrt(n*n+n*n);AngleStep(45);}
else if (op=='f') {n=Math.sqrt(n*n+n*n);AngleStep(315);}
else if (op=='g') {n=Math.sqrt(n*n+n*n);AngleStep(225);}
else if (op=='h') {n=Math.sqrt(n*n+n*n);AngleStep(135);}
else if (op=='w') {AngleStep(45);}
else if (op=='x') {AngleStep(315);}
else if (op=='y') {AngleStep(225);}
else if (op=='z') {AngleStep(135);}
} else if (m = cmds.match(/^(m)([+-]?)([0-9]+)[,]([+-]?[0-9]+)/)) {
var op = m[1];
var sx = m[2];
var x = parseInt(m[3]);
var y = parseInt(m[4]);
if (sx) {
x = parseInt(sx + '1') * x;
Step(x, y);
} else {
StepUnscaled(x - pen_x, y - pen_y);
}
} else if (m = cmds.match(/^(p)([0-9]+),([0-9]+1)/)) {
var op = m[1];
var x = parseInt(m[2]);
var y = parseInt(m[3]);
// TODO: Implement.
} else if (m = cmds.match(/^(b|n)/)) {
var op = m[1];
if (op == 'b') {
draw_state.noplot = true;
} else if (op == 'n') {
draw_state.nomove = true;
}
} else {
Throw('Bad drop op: ' + cmds);
}
cmds = cmds.substr(m[0].length);
}
}
function Paint(x, y, paint, border) {
paint = FixupColor(paint);
if (border === undefined) {
border = paint;
} else {
border = FixupColor(border) & 0xffffff;
}
var fpaint = paint & 0xffffff;
var data = display_data;
var pending = [];
pending.push([Math.floor(x), Math.floor(y)]);
while (pending.length) {
var p = pending.pop();
if (p[0] < 0 || p[0] >= display.width ||
p[1] < 0 || p[1] >= display.height) {
continue;
}
var pos = p[0] + p[1] * display.width;
if ((data[pos] & 0xffffff) == border ||
(data[pos] & 0xffffff) == fpaint) {
continue;
}
data[pos] = paint;
pending.push([p[0] - 1, p[1]]);
pending.push([p[0] + 1, p[1]]);
pending.push([p[0], p[1] - 1]);
pending.push([p[0], p[1] + 1]);
}
}
function GetVar() {
var name = tok;
Next();
return IndexVariable(name, true);
}
var DEFAULT_TYPES = {
'defdbl': 'double',
'defsng': 'single',
'defint': 'short',
'deflng': 'long',
'defstr': 'string',
};
function Statement() {
if (EndOfStatement()) {
// Ignore empty lines.
} else if (tok == 'rem') {
do {
Next();
} while (tok != '');
} else if (tok == 'if') {
Skip('if');
var e = Expression();
var kw=tok;
if (kw=='goto') {Skip(kw);}
else {Skip('then');}
if (EndOfStatement()) {
If(e);
while (tok == ':') {
Skip(':');
Statement();
}
if (tok == 'else') {
Skip('else');
Else();
while (tok == ':') {
Skip(':');
Statement();
}
}
if (tok == 'end') {
Skip('end');
Skip('if');
EndIf();
}
} else {
// Classic if then
If(e);
if ((kw=='goto')||(tok.match(/^[0-9]+$/))) {
var name = tok;
Next();
curop += 'if (LabelExists("'+name+'")==-1) {ip = labels[("' + name + '").replace(/^0+/, "")];} else {BadLabel("'+name+'");}\n';
NewOp();
} else {
Statement();
while (tok==':') {
Skip(':');
Statement();
}
}
var f = flow.pop();
if (f[0]!='if') {
Throw('If in mixed style');
}
flow.push(f);
NewOp();
if (tok=='else') {
Skip('else');
Else();
if ((kw=='goto')||tok.match(/^[0-9]+$/)) {
var name = tok;
Next();
curop += 'if (LabelExists("'+name+'")==-1) {ip = labels[("' + name + '").replace(/^0+/, "")];} else {BadLabel("'+name+'");}\n';
NewOp();
} else {
Statement();
while (tok==':') {
Skip(':');
Statement();
} }
}
EndIf();
}
} else if (tok=='elseif') {
Skip(tok);
var e=Expression();
Skip('then');
ElseIf(e);
} else if (tok=='else') {
Skip(tok);
Else();
if (!EndOfStatement()) {Statement();}
} else if (tok=='do') {
Skip(tok);
if (tok=='while') {
// Support DO WHILE
Statement();
return;
}
NewOp();
flow.push(['do', ops.length]);
} else if (tok=='loop') {
Skip(tok);
var is_while;
if (tok=='while') {
Skip(tok);
is_while=true;
} else if (tok=='until') {
Skip(tok);
is_while=false;
} else if (EndOfStatement()) {
var f=flow.pop();
if (f[0] != 'while' && f[0] != 'do') {Throw('LOOP does not match DO / WHILE');}
curop+='ip = '+f[1]+';\n';
NewOp();
if (f[0]=='while') {ops[f[1]] += ops.length + '; }\n';}
return;
} else {Throw('Expected while/until');}
var e = Expression();
var f = flow.pop();
if (f[0]!='do') {Throw('LOOP does not match DO');}
if (is_while) {curop += 'if ('+e+') {ip='+f[1]+'; }\n';}
else {curop += 'if (!('+e+')) {ip='+f[1]+';}\n';}
NewOp();
} else if (tok=='while') {
Skip(tok);
var e=Expression();
NewOp();
curop+='if (!('+e+')) {ip=';
NewOp();
flow.push(['while',ops.length-1]);
} else if (tok=='wend') {
Skip(tok);
var f = flow.pop();
if (f[0]!='while') {Throw('Wend does not match while');}
curop += 'ip = ' + f[1] + ';\n';
NewOp();
ops[f[1]] += ops.length + '; }\n';
} else if (tok == 'exit') {
Skip('exit');
if (tok == 'sub') {
Skip('sub');
FunctionExit();
} else if (tok == 'function') {
Skip('function');
FunctionExit();
} else {
Throw('Exit only works with SUB and FUNCTION');
}
} else if (tok == 'end') {
Skip('end');
if (tok == 'if') {
Skip('if');
EndIf();
} else if (tok == 'select') {
Skip('select');
NewOp();
var f = flow.pop();
if (f[0] != 'select') {
Throw('end select outside select');
}
var disp = 'var t = (' + f[1] + ');\n';
disp += 'if (false) {}\n';
for (var i = 0; i < f[3].length; i++) {
var ii = f[3][i];
if (ii[0] == ii[1]) {
disp += 'else if (t == (' + ii[0] +
')) { ip = ' + ii[2] + '; }\n';
} else {
disp += 'else if (t >= (' + ii[0] + ') && t <= (' + ii[1] +
')) { ip = ' + ii[2] + '; }\n';
}
}
if (f[5] !== null) {
disp += 'else { ip = ' + f[5] + '; }\n';
} else {
disp += 'else { ip = ' + ops.length + '; }\n';
}
ops[f[2]] += disp;
for (var i = 0; i < f[4].length; i++) {
ops[f[4][i]] += 'ip = ' + ops.length + ';\n';
}
} else if (tok == 'sub') {
Skip('sub');
FunctionEnd();
sub_check = sub_check - 1;
} else if (tok == 'function') {
Skip('function');
FunctionEnd();
fn_check = fn_check - 1;
} else {
curop += 'End();\n';
}
} else if (tok=='stop') {
Skip(tok);
Throw('BREAK');
} else if (tok=='goto') {
Skip(tok);
var name = tok;
if (tok=='eval') {Skip(tok);Skip('(');name=Expression();Skip(')');curop += 'if (LabelExists(('+name+').toString())==-1) {ip = labels[((' + name + '.toString()).toLowerCase()).replace(/^0+/, "")];} else {BadLabel('+name+');}\n';}
else {Next();curop += 'if (LabelExists("'+name+'")==-1) {ip = labels[("' + name + '").replace(/^0+/, "")];} else {BadLabel("'+name+'");}\n';}
NewOp();
} else if (tok=='gosub') {
Skip(tok);
var name = tok;
curop += 'i[sp>>2] = ip; sp += 8;\n';
if (tok=='eval') {Skip(tok);Skip('(');name=Expression();Skip(')');curop += 'if (LabelExists(('+name+').toString())==-1) {ip = labels[((' + name + '.toString()).toLowerCase()).replace(/^0+/, "")];} else {BadLabel('+name+');}\n';}
else {Next();curop += 'if (LabelExists("'+name+'")==-1) {ip = labels[("' + name + '").replace(/^0+/, "")];} else {BadLabel("'+name+'");}\n';}
NewOp();
} else if (tok=='return') {
Skip(tok);
curop += 'sp-=8;ip=i[sp>>2];\n';
NewOp();
} else if (tok=='declare') {
Skip(tok);
if (tok=='sub') {Skip(tok);FunctionDefine({is_subroutine: true, is_declaration: true});}
else if (tok=='function') {Skip(tok);FunctionDefine({is_subroutine: false, is_declaration: true});}
else {Throw('Unexpected declaration');}
} else if (tok=='type'||tok=='struct'||tok=='structure'||tok=='record') {
var lbl=tok;
var old_allocated = allocated;
vars = {};
Skip(tok);
var type_name = tok;
Next();
if (types[type_name]!==undefined) {Throw('Duplicate type definition');}
types[type_name]={vars: vars,size: 0,};
inside_type=true;
var_decls+='// TYPE '+type_name+'\n';
SkipEndOfStatement();
while (tok!='end') {
while (!EndOfStatement()) {
DimVariable(null);
while (tok == ',') {Skip(',');DimVariable(null);}
}
SkipEndOfStatement();
}
Skip('end');
Skip(lbl);
inside_type=false;
types[type_name].size=allocated;
vars=global_vars;
allocated=old_allocated;
} else if (tok=='defdv') {
Skip(tok);
for (;;) {
var fname = tok;
var pos = FunctionDefine({is_subroutine: false});
Skip('=');
var e = Expression();
curop += IndexVariable(fname, true) + ' = ' + e + ';\n';
FunctionEnd(pos);
if (tok == ',') {
Skip(',');
continue;
}
break;
}
} else if (tok=='let') {
var kw=tok;
Skip(tok);
while (!EndOfStatement()) {
if (tok==',') {Skip(',');}
var name = tok;
Next();
var vname = IndexVariable(name, true);
if (constants_list.indexOf('C'+name+'C')>-1) {
Throw('A constant named "'+name+'" already exists.');}
if (tok=='=' || tok=='+=' || tok=='-=' ||
tok=='*=' || tok=='/=' || tok=='\\=' ||
tok=='^=' || tok=='&=') {
var op = tok;
Skip(tok);
var e = Expression();
if (op == '&=') {
op = '+=';
} else if (op == '\\=') {
op = '//=';
}
if (op == '^=') {curop += vname + ' = Math.pow(' + vname + ', ' + e + ');\n';}
else {curop += vname + ' ' + op + ' (' + e + ');\n';}
} else {
Throw('Expected "=" or "x=" found "' + tok + '"\n\n(assuming assignment to a variable; could be a case of a misspelled keyword)');
}}
} else if (tok=='dim'||tok=='redim'||tok=='var'||tok=='const') {
var op=tok;
Next();
if (tok=='shared') {
Skip('shared');
}
var tname = null;
if (tok=='as') {
Skip('as');
tname=TypeName();
}
IsKeyword(tok);
if (op=='const' && constants_list.indexOf('C'+tok+'C')==-1)
{constants_list=constants_list+'C'+tok+'C';}
else if (constants_list.indexOf('C'+tok+'C')>-1) {Throw('A constant named "'+tok+'" already exists.');}
DimVariable(tname,op=='redim');
while (tok==',') {
Skip(',');
DimVariable(tname,op=='redim');
}
} else if (tok == 'on') {
Skip(tok);
var name=Expression();
var kw=tok;
var i=0;
if (kw=='error') {Skip('error');}
else {
Next();if (EndOfStatement()) {Throw('Expected labels.');}
var rlbls = ' ';
while (!(EndOfStatement())) {
rlbls+=String(tok);
i+=1;
Next();
if (EndOfStatement()) {}
else {rlbls+=',';Skip(',');}
}
rlbls=rlbls.replace(/\s+/g, '');
curop += 'if ('+name+'>'+i+') {Throw("Not enough labels for [on ' + kw + '].",false);}';
if (kw=='restore') {
curop += 'if (LabelExists("'+rlbls+'".split(",")['+name+'-1])==-1) {data_pos = data_labels["'+rlbls+'".split(",")['+name+'-1].replace(/^0+/, "")];} else {BadLabel("'+rlbls+'".split(",")['+name+'-1]);}\n';
}
else if (kw=='goto' || kw=='gosub') {
if (kw=='gosub') {curop += 'i[sp>>2] = ip; sp += 8;\n';}
curop += 'if (LabelExists("'+rlbls+'".split(",")['+name+'-1])==-1) {ip = labels["'+rlbls+'".split(",")['+name+'-1].replace(/^0+/, "")];} else {BadLabel("'+rlbls+'".split(",")['+name+'-1]);}\n';
}
else {Throw('Expected GOTO,GOSUB,RESTORE, or ERROR. Found ' + kw);}
NewOp();
}
} else if (tok == 'resume') {
Skip('resume');
if (tok == 'next') {
Skip('next');
// TODO: Implement.
} else if (tok == '0') {
Skip('0');
// TODO: Implement.
} else if (!EndOfStatement()) {
var name = tok;
Next();
// TODO: Implement.
} else {
// TODO: Implement.
}
} else if (tok == 'sub') {
Skip('sub');
FunctionDefine({is_subroutine: true});
sub_check = sub_check + 1;
} else if (tok == 'function') {
Skip('function');
FunctionDefine({is_subroutine: false});
fn_check = fn_check + 1;
} else if (tok == 'def') {
Skip('def');
if (tok == 'seg') {
Skip('seg');
if (tok == '=') {
Skip('=');
var e = Expression();
// TODO: Do something useful with it?
}
} else if (tok.substr(0, 2) == 'fn') {
if (tok=='fn') {Skip(tok);}
var fname = tok;
var pos = FunctionDefine({is_subroutine: false});
Skip('=');
var e = Expression();
curop += IndexVariable(fname, true) + ' = ' + e + ';\n';
FunctionEnd(pos);
} else {
Throw('Expected SEG/FNxxx');
}
} else if (tok == 'open') {
Skip(tok);
var fname = Expression();
Skip('for');
var fmode = '"' + tok + '"';
if (tok == 'input') {
Skip(tok);
} else if (tok == 'output') {
Skip(tok);
} else {
Throw('Expected input/output');
}
Skip('as');
tok=tok.replace('#','');
var fnum = Expression();
curop += 'fOpen(' + fname + ',' + fmode + ',' + fnum + ');\n';
NewOp();
} else if (tok == 'close') {
Skip(tok);
tok=tok.replace('#','');
var fnum = Expression();
// Skip(tok);
curop += 'fClose(' + fnum + ');\n';
NewOp();
} else if (tok == 'system') {
Skip(tok);
// TODO: Implement.
} else if (tok == 'donothing') {
Skip(tok);
} else if (/^([_]?keyclear)$/.test(tok)) {
// tok=='keyclear'||tok=='_keyclear') {
Skip(tok);
curop += 'KeyClear();\n';
NewOp();
} else if (tok == 'beep') {
Skip(tok);
curop += 'Sound(800,1);\n';
NewOp();
} else if (tok == 'view') {
Skip('view');
if (tok == 'print') {
Skip('print');
if (!EndOfStatement()) {
var top = Expression();
Skip('to');
var bottom = Expression();
}
// TODO: Implement.
} else if (tok == 'screen') {
Skip('screen');
// TODO: Implement.
} else {
Throw('Expected PRINT/SCREEN');
}
} else if (tok == 'randomize') {
Skip('randomize');
if (!EndOfStatement()) {var seed = Expression();}
// Ignore
} else if (tok == 'poke') {
Skip('poke');
var addr = Expression();
Skip(',');
var value = Expression();
// TODO: Do something useful with it?
} else if (tok == 'key') {
Skip('key');
if (tok == 'on') {
Skip('on');
} else if (tok == 'off') {
Skip('off');
} else {
Throw('Expected on/off');
}
// Implement this?
} else if (tok == 'setclipboardtext') {
Skip(tok);
Skip('(');
var t = Expression();
Skip(')');
curop += 'SetClipboardText(' + t + ');\n';
NewOp();
} else if (tok=='lprint') {
Skip(tok); var t=Expression(); curop += 'Lprint(' + t + ');\n'; NewOp();
} else if (tok=='_dumpvars') {
Skip(tok); curop+='SetClipboardText(JSON.stringify(vars,null,2));\n'; NewOp();
} else if (tok=='mapset') {
Skip(tok); Skip('(');
var k=Expression(); Skip(','); var v=Expression(); Skip(')');
curop+='MapSet('+k+','+v+');\n'; NewOp();
} else if (tok=='clearlocalstorage') {
Skip(tok); curop+='ClearLocalStorage();\n'; NewOp();
} else if (tok == 'removelocalstorageitem') {
Skip(tok);
Skip('(');
var k = Expression();
Skip(')');
curop += 'RemoveLocalStorageItem(' + k + ');\n';
NewOp();
} else if (tok == 'setlocalstorageitem') {
Skip(tok);
Skip('(');
var k = Expression();
Skip(',');
var v = Expression();
Skip(')');
curop += 'SetLocalStorageItem(' + k + ',' + v + ');\n';
NewOp();
} else if (tok == 'removelocalstorageitem') {
Skip(tok);
Skip('(');
var k = Expression();
Skip(')');
curop += 'localStorage.removeitem("' + k + '");\n';
NewOp();
} else if (tok == 'setsessionstorageitem') {
Skip(tok);
Skip('(');
var k = Expression();
Skip(',');
var v = Expression();
Skip(')');
curop += 'SetSessionStorageItem(' + k + ',' + v + ');\n';
NewOp();
} else if (tok == 'letchr$') {
Skip(tok); Skip('('); var k = Expression();
Skip(','); var v = Expression(); Skip(')');
curop += 'LetChr(' + k + ',' + v + ');\n'; NewOp();
} else if (tok == 'sound') {
Skip(tok);
var freq = Expression();
Skip(',');
var duration = Expression();
curop += 'Sound(' + freq + ',' + duration + ');\n';
NewOp();
} else if (tok == '_initaudio') {
Skip(tok);
curop += 'InitAudio();\n';
NewOp();
curop += 'Sound(10,18.2);\n';
NewOp();
curop += 'Sleep(1.25);\n';
NewOp();
} else if (tok == '_finishaudio') {
Skip(tok);
curop += 'Sleep(audio_queue_timer-GetTimer());\n';
NewOp();
} else if (tok=='_endaudio') {
Skip(tok);
curop+='EndAudio();\n';
NewOp();
} else if (tok=='_sndwave') {
Skip(tok);
var w=Expression();
curop+='sndwave=('+w+').toLowerCase();\n';
NewOp();
} else if (tok=='_sndfade') {
Skip(tok);
var w=Expression();
curop+='sndfade=('+w+').toLowerCase();\n';
NewOp();
} else if (tok=='play') {
Skip('play');
var notes=Expression();
// TODO
} else if (tok=='_startspool') {
Skip(tok);
var w=Expression();
curop+='spool_name='+w+';\n';
NewOp();
} else if (tok=='_endspool') {
Skip(tok);
curop+='EndSpool();\n';
NewOp();
} else if (tok=='_cancelspool') {
Skip(tok);
curop += 'CancelSpool();\n';
NewOp();
} else if (tok=='draw') {
Skip(tok);
var cmds=Expression();
curop+='Draw(' + cmds + ');\n';
} else if (tok == 'chain') {
Skip(tok);
var filename = Expression();
if (tok == ',') {
Skip(',');
var name = tok;
Next();
}
// TODO: Implement this.
} else if (tok == 'option') {
Skip(tok);
if (tok == 'explicit' || tok =='_explicit' ) {
Skip(tok);
option_explicit = true;
} else if (tok == 'base') {
Skip(tok);
if (tok == '0') {
option_base = 0;
} else if (tok == '1') {
option_base = 1;
} else {
Throw('Unexpected option base "' + tok + '"');
}
Next();
} else {
Throw('Unexpected option "' + tok + '"');
}
} else if (tok=='defdbl'||tok=='defsng'||tok=='deflng'||tok=='defint'||tok=='defstr') {
var def_type = tok;
Next();
for (;;) {
var start = tok;
var end;
Next();
if (EndOfStatement()||tok==',') {end=start;}
else {Skip('-');end=tok;Next();}
if (!start.match(/^[a-z]$/) ||
!end.match(/^[a-z]$/) ||
start.charCodeAt(0) > end.charCodeAt(0)) {
Throw('Invalid variable range');
}
var i = start;
do {
letter_default[i] = DEFAULT_TYPES[def_type];
i = NextChar(i);
} while (i <= end);
if (tok == ',') {
Skip(',');
continue;
}
break;
}
} else if (tok == 'for') {
Skip('for');
var name = tok;
var v = IndexVariable(name, true);
Next();
Skip('=');
var start = Expression();
Skip('to');
var end = Expression();
var step = 1;
if (tok == 'step') {
Skip('step');
step = Expression();
curop += 'if ('+step+'==0) {Throw("STEP value of zero not allowed",false);}\n';
NewOp();
}
curop += v + ' = (' + start + ');';
NewOp();
curop += 'if (((' + step + ' > 0) && ' +
v + ' > (' + end + ')) || ' +
'((' + step + ' < 0) && ' +
v + ' < (' + end + '))) { ip = ';
NewOp();
flow.push(['for', v, ops.length - 1, step]);
} else if (tok == 'next') {
function AddOp() {
curop += f[1] + ' += (' + f[3] + ');\n';
curop += 'ip = ' + f[2] + ';\n';
NewOp();
ops[f[2]] += ops.length + '; }\n';
}
Skip(tok);
var yup=1;
while (yup==1) {
var f = flow.pop();
if (f[0] != 'for') {
Throw('Expected NEXT');
}
if (!EndOfStatement()) {
var name = tok;
// TODO: Shouldn't this fail?
/*
if (name != f[1]) {
Throw('Expected ' + f[1]);
}
*/
Next();
}
AddOp();
if (!EndOfStatement()) {
Skip(',');
}
else {yup=0;}
}
} else if (tok == 'paint') {
Skip(tok);
var do_step=0; if (tok=='step') {do_step=1;Skip(tok);}
Skip('(');
var x = Expression();
Skip(',');
var y = Expression();
Skip(')');
if (do_step==1) {x='pen_x+'+x; y='pen_y+'+y;}
var paint;
if (tok == ',') {
Skip(',');
paint = Expression();
}
var border;
if (tok == ',') {
Skip(',');
border = Expression();
}
curop += 'Paint((' + x + '), (' + y + '), (' +
paint + '), (' + border + '));\n';
} else if (tok == 'circle') {
var s = tok;
Skip(tok);
var do_step=0; if (tok=='step') {do_step=1; Skip(tok);}
Skip('(');
var x = Expression();
Skip(',');
var y = Expression();
Skip(')');
if (do_step==1) {x='pen_x+'+x; y='pen_y+'+y;}
Skip(',');
var r = Expression();
var c = 'undefined';
if (tok == ',') {
Skip(',');
if (tok != ',' && !EndOfStatement()) {
c = Expression();
}
}
var start = 0;
var end = Math.PI * 3;
var aspect = 'null';
var fill = 0;
if (tok == ',') {
Skip(',');
if (tok != ',' && !EndOfStatement()) {
start = Expression();
}
}
if (tok == ',') {
Skip(',');
if (tok != ',' && !EndOfStatement()) {
end = Expression();
}
}
if (tok == ',') {
Skip(',');
if (tok != ',' && !EndOfStatement()) {
aspect = Expression();
}
}
if (tok == ',') {
Skip(',');
if (tok=='f'||tok=='t') {
if (tok=='f') {fill=1} else {fill=2};
Next();
} else {
Throw('Expected F (fill) or T (thick), got ' + tok);
}
}
curop += 'Circle((' + [x,y,r,c,start,end,aspect,fill].join('),(') + '));\n';
} else if (tok=='pset'||tok=='plot'||tok=='preset'||tok=='unplot') {
var c=-1;
if (tok=='pset'||tok=='plot') {c=-2;}
Next();
var do_step=0; if (tok=='step') {do_step=1; Skip(tok);}
Skip('(');
var x=Expression();
Skip(',');
var y=Expression();
Skip(')');
if (do_step==1) {x = 'pen_x+'+x; y = 'pen_y+'+y;}
if (tok==',') {Skip(',');c=Expression();}
curop+='Pset('+x+','+y+','+c+');\n';
} else if (tok=='line') {
Skip(tok);
if (tok=='input') {
var crlf=1;
Skip(tok);
if (tok==';') {crlf=0;Skip(';');}
var prompt='""';
if (tok.substr(0, 1)=='"') {
var prompt=tok;
Next();
Skip(';');
// if (tok == ';' || tok == ',') {
// Next();
// }
}
curop += 'Print([' + prompt + ', ";"],"p", null);\n';
curop += 'PutCh(String.fromCharCode(219));\n';
curop += 'input_string = ""\n';
NewOp();
curop += 'LineInput('+crlf+');\n';
NewOp();
var a = GetVar();
curop += a + ' = input_string;\n';
return;
}
var x1='pen_x';
var y1='pen_y';
var do_step=0;
if (tok=='step') {do_step=1;Skip(tok);}
if (tok=='(') {
Skip('(');
x1 = Expression();
Skip(',');
y1 = Expression();
Skip(')');
if (do_step==1) {x1='pen_x+'+x1;y1='pen_y+'+y1;}
}
if (tok=='to') {Skip(tok)}
else {Skip('-')}
do_step=0;
if (tok=='step') {do_step=1;Skip(tok);}
Skip('(');
var x2=Expression();
Skip(',');
var y2=Expression();
Skip(')');
if (do_step==1) {x2 = x1+'+'+x2;y2 = y1+'+'+y2;}
var c='undefined';
var fill=0;
if (tok==',') {
Skip(',');
if (tok!=',') {c=Expression();}
if (tok==',') {
Skip(',');
if (tok=='b') {fill=1;}
else if (tok=='bf') {fill=2;}
else {Throw('Unexpected '+tok);}
Next();
}
}
curop += 'Line2((' +
[x1, y1, x2, y2, c, fill].join('), (') + '));\n';
} else if (tok == 'get') {
Skip('get');
Skip('(');
var x1 = Expression();
Skip(',');
var y1 = Expression();
Skip(')');
Skip('-');
Skip('(');
var x2 = Expression();
Skip(',');
var y2 = Expression();
Skip(')');
Skip(',');
var name = tok;
Next();
var v = ArrayPart(ReserveArrayCell(name).offset, 0);
curop += 'GetImage(' + x1 + ', ' + y1 + ', ' +
x2 + ', ' + y2 + ', buffer, ' + v + ');\n';
} else if (tok == 'put') {
Skip('put');
var do_step=0; if (tok=='step') {do_step=1; Skip(tok);}
Skip('(');
var x = Expression();
Skip(',');
var y = Expression();
Skip(')');
if (do_step==1) {x='pen_x+'+x; y='pen_y+'+y;}
Skip(',');
var name = tok;
Next();
var v = ArrayPart(ReserveArrayCell(name).offset, 0);
var mode = 'xor';
if (tok == ',') {
Skip(',');
if (tok == 'pset' || tok == 'preset' || tok == 'and' ||
tok == 'or' || tok == 'xor') {
mode = tok;
Next();
} else {
Throw('Invalid put mode');
}
}
curop += 'PutImage(' + x + ', ' + y + ', buffer, ' +
v + ', "' + mode + '");\n';
} else if (tok == 'screen') {
Skip(tok);
var ret = 'Screen(';
if (tok == '_newimage') {
Skip(tok);
Skip('(');
var m0 = Expression();
Skip(',');
var m1 = Expression();
Skip(',');
var e = Expression();
Skip(')');
} else {
var e = Expression();
var m0;
var m1;
}
ret += '' + e + ', ' + m0 + ', ' + m1 + '';
while (tok == ',') {
Skip(',');
if (tok != ',' && !EndOfStatement()) {
var e = Expression();
ret += ', (' + e + ')';
} else {
ret += ', null';
}
}
ret += ');\n'
curop += ret;
} else if (tok=='cls') {
Skip('cls');
var mode='0';
if (tok=='0'||tok=='1'||tok=='2') {
mode = tok;
Next();
}
curop+='Cls('+mode+');\n';
} else if (tok=='sleep'||tok=='_delay') {
Skip(tok);
if (EndOfStatement()) {curop+='SleepUntilKey=1;\n';}
else {var e=Expression();curop+='if ('+e+'==0) {SleepUntilKey=1;} else {Sleep('+e+');}\n';}
NewOp();
} else if (tok == 'pcopy') {
Skip(tok);
var x1; var y1; var x2; var y2;
if (tok=='(') {
Skip('(');x1=Expression();Skip(',');y1=Expression();Skip(')');
Skip('-');
Skip('(');x2=Expression();Skip(',');y2=Expression();Skip(')');
Skip(',');
}
var a = Expression();
Skip(',');
var b = Expression();
curop += 'Pcopy('+x1+','+y1+','+x2+','+y2+','+a+','+b+');\n';
NewOp();
} else if (tok=='scroll') {
Skip(tok);
var x1; var y1; var x2; var y2;
if (tok=='(') {
Skip('(');x1=Expression();Skip(',');y1=Expression();Skip(')');
if (tok=='to') {Skip(tok);} else {Skip('-');}
Skip('(');x2=Expression();Skip(',');y2=Expression();Skip(')');
Skip(',');
}
var h=Expression();Skip(',');var v=Expression();
var w = 0;
if (tok==',') {Skip(',');w=Expression();}
curop+='Scroll('+x1+','+y1+','+x2+','+y2+','+h+','+v+','+w+');\n';
NewOp();
} else if (tok=='_limit') {
Skip(tok);
var e=Expression();
} else if (tok=='_title') {
Skip(tok);
var e=Expression();
curop+='document.title='+e+';\n';
NewOp();
} else if (tok=='_autodisplay') {
Skip(tok);
curop+='autodisplay = 1;\n';
NewOp();
curop+='display_now = 0;\n';
NewOp();
} else if (tok=='_display') {
Skip(tok);
curop+='autodisplay = 0;\n';
NewOp();
curop+='display_now = 1;\n';
NewOp();
} else if (tok=='alert') {
Skip(tok);
Skip('(');
var e=Expression();
Skip(')');
curop+='Sleep(0.005);\n';
NewOp();
curop+='alert('+e+');\n';
NewOp();
curop+='mouse_buttons=0;\n';
NewOp();
curop+='KeyClear();\n';
NewOp();
curop+='canvas.focus();\n';
NewOp();
} else if (tok=='consolelog') {
Skip(tok);
Skip('(');
if (tok=='ops') {var e = 'ops.toString()';Skip(tok);}
else {var e=Expression();}
Skip(')');
curop+='Sleep(0.005);\n';
NewOp();
curop+='console.log('+e+');\n';
NewOp();
} else if (tok=='_openwindow') {
Skip(tok);
Skip('(');
var e=Expression();
Skip(')');
curop+='Sleep(0.005);\n';
NewOp();
curop+='OpenWindow('+e+');\n';
NewOp();
} else if (tok=='locate') {
Skip(tok);var y='0';var x='0';
if (tok!=',' && !EndOfStatement()) {y=Expression();}
if (tok == ',') {Skip(',');x=Expression();}
if (tok == ',') {
Skip(',');
var cursor = Expression();
// TODO: Support cursor + start + stop
}
curop+='Locate(Math.trunc('+x+'),Math.trunc('+y+'));\n';
} else if (tok=='width') {
Skip(tok);
var w=Expression();
if (tok==',') {
Skip(',');
var n = Expression();
// TODO
}
curop+='Width('+w+');curr_width='+w+'*8;window.dispatchEvent(new Event("resize"));\n';
} else if (tok=='height') {
Skip(tok);
var w = Expression();
if (tok == ',') {
Skip(',');
var n = Expression();
// TODO
}
curop += 'Height(' + w + ');curr_height='+w+'*font_height;window.dispatchEvent(new Event("resize"));\n';
} else if (tok == 'color') {
Skip('color');
var fg;
var bg;
if (tok != ',') fg = Expression();
if (tok == ',') {
Skip(',');
bg = Expression();
}
if (tok == ',') {
Skip(',');
var cursor = Expression();
// TODO: Support cursor
}
curop += 'Color(' + fg + ',' + bg + ');\n';
} else if (tok == 'palette') {
Skip(tok);
if (!EndOfStatement()) {
var c = Expression();
Skip(',');
var p = Expression();
curop += 'Palette(' + c + ',' + p + ');\n';
}
else { curop += 'InitPalette();\n';
}
} else if (tok == 'swap') {
Skip(tok);
if (constants_list.indexOf('C'+tok+'C')>-1) {Throw('SWAP with constant "'+tok+'" not allowed.');}
var a = GetVar();
Skip(',');
if (constants_list.indexOf('C'+tok+'C')>-1) {Throw('SWAP with constant "'+tok+'" not allowed.');}
var b = GetVar();
curop += 'var t = ' + a + ';\n';
curop += a + ' = ' + b + ';\n';
curop += b + ' = t' + ';\n';
} else if (tok == 'mid$') {
Skip(tok);
Skip('(');
var a = GetVar();
Skip(',');
var b = Expression();
var c = "0";
if (tok == ",") {
Skip(',');
c = Expression();
}
Skip(')');
Skip('=');
var d = Expression();
var thisop = '(' + a + ').substr( 0, (' + b + ') -1)';
var tempop = '(' + thisop +').concat( "", (' + d + ')';
if (c !== "0") {
tempop = tempop + '.substr(0,' + c + ')';
}
thisop = tempop + ')';
thisop = '(' + thisop + ').substr(0, (' + a + ').length)';
thisop = '(' + thisop + ').concat( "", (' + a + ').slice((' + thisop + ').length))';
curop += a + ' = ' + thisop + ';\n';
} else if (tok == 'data') {
ConsumeData();
} else if (tok == 'read') {
Skip('read');
curop += 'if(data[data_pos]==undefined) {Throw("OUT OF DATA");}\n';
curop += GetVar() + ' = data[data_pos++];\n';
while (tok == ',') {
Skip(',');
curop += GetVar() + ' = data[data_pos++];\n';
}
} else if (tok == 'restore') {
Skip('restore');
if (!EndOfStatement()) {
var name = tok;
if (tok=='eval') {Skip(tok);Skip('(');name=Expression();Skip(')');curop += 'if (LabelExists(('+name+').toString())==-1) {data_pos = data_labels[((' + name + '.toString()).toLowerCase()).replace(/^0+/, "")];} else {BadLabel('+name+');}\n';}
else {curop += 'if (LabelExists("'+name+'")==-1) {data_pos = data_labels[("' + name + '").replace(/^0+/, "")];} else {BadLabel("'+name+'");}\n';Next();}
} else {
curop += 'data_pos = 0;\n';
}
} else if (tok == 'input') {
var crlf=1;
Skip(tok);
if (tok[0] == '#') {
// TODO: Implement.
Next();
if (tok == ';' || tok == ',') {
Next();
}
}
if (tok == ';') {
crlf=0; Skip(';');
}
var prompt = '"? "';
if (tok.substr(0, 1) == '"') {
var prompt = tok;
Next();
if (tok==';' || tok==',') {
if (tok==';') {prompt=prompt.substring(0,prompt.length-1)+'? "'}
Next();
}
}
curop += 'Print([' + prompt + ', ";"],"p",null);\n';
curop += 'PutCh(String.fromCharCode(219));\n';
curop += 'input_string = ""\n';
NewOp();
curop += 'LineInput('+crlf+');\n';
NewOp();
var n = 0;
while (!EndOfStatement()) {
curop += GetVar() + ' = input_string.split(",")[' + n++ + '];\n';
if (tok != ',') {
break;
}
Skip(',');
}
} else if (tok=='print'||tok=='?'||tok=='write'||tok.substring(0,6)=='print#'||tok.substring(0,6)=='write#') {
var sttmnt=tok.substring(0,1);
var fnum = null;
if (tok.substring(0,6)=='print#') {
tok = tok.replace('print#','');
fnum = Expression();
}
else if (tok.substring(0,6)=='write#') {
tok = tok.replace('write#','');
fnum = Expression();
}
else {
Skip(tok);
if (tok.charAt(0)=='#') {
tok = tok.replace('#','');
fnum = Expression();
}
}
if (EndOfStatement()) {
if (fnum !== null) {
curop += 'fPrint('+ fnum + ',"","p");\n';
}
else {
curop += 'Print([],"p",null);\n';
}
return;
}
if (fnum !== null) {
Skip(',');
}
var fmt = null;
if (tok == 'using') {
Skip('using');
fmt = Expression();
Skip(';');
}
var items = [];
var e = Expression();
items.push(e);
while (tok == ';' || tok == ',') {
if (fnum==null) {
items.push('"' + tok + '"');
}
else {
if (sttmnt=='w') {items.push('","');}
else {items.push('"' + tok + '"');}
}
Next();
if (tok == 'else') {
break;
} // cjv
if (EndOfStatement()) {
break;
}
var e = Expression();
items.push(e);
}
if (fnum !== null) {
// curop += 'fPrint(' + fnum + ',' + items.join(' + ') + ',"' + sttmnt + '");\n';
curop += 'Print([' + items.join(', ') + '],"' + sttmnt + '",' + fnum + ');\n';
}
else if (fmt !== null) {
curop += 'PrintUsing(' + fmt + ', [' + items.join(', ') + ']);\n';
} else {
curop += 'Print([' + items.join(', ') + '],"' + sttmnt + '",' + fnum + ');\n';
}
} else if (tok == 'select') {
Skip('select');
Skip('case');
if (tok == 'as') {
Skip('as');
Skip('const');
}
var e = Expression();
NewOp();
flow.push(['select', e, ops.length - 1, [], [], null]);
} else if (tok == 'case') {
Skip('case');
var f = flow.pop();
if (f[0] != 'select') {
Throw('Case outside select');
}
NewOp();
f[4].push(ops.length - 1);
if (tok == 'else') {
Skip('else');
f[5] = ops.length;
flow.push(f);
return;
}
function Accept(t) {
if (tok == t) {
Next();
return true;
}
return false;
}
do {
var e = Expression();
if (tok == 'to') {
Skip('to');
var e1 = Expression();
f[3].push([e, e1, ops.length]);
} else {
f[3].push([e, e, ops.length]);
}
} while (Accept(','));
flow.push(f);
} else if (tok == 'getmouse') {
Skip('getmouse');
curop += 'Yield();';
NewOp();
curop += GetVar() + ' = mouse_x;\n';
Skip(',');
curop += GetVar() + ' = mouse_y;\n';
if (tok == ',') {
Skip(',');
if (tok != ',') {
curop += GetVar() + ' = mouse_wheel;\n';
}
}
if (tok == ',') {
Skip(',');
if (tok != ',') {
curop += GetVar() + ' = mouse_buttons;\n';
}
}
if (tok == ',') {
Skip(',');
curop += GetVar() + ' = mouse_clip;\n';
}
} else if (tok=='') {
return;
} else if (tok=='call' || (functions[tok] !== undefined &&
functions[tok].is_subroutine)) {
var name=tok;
Next();
if (name=='call') {
name=tok;
Next();
FunctionCall(name,{is_subroutine:true,is_call:true});
} else {
NoEekOnSkip=1;
FunctionCall(name,{is_subroutine: true});
NoEekOnSkip=0;
}
} else {
var name = tok;
Next();
if (tok == ':') {
Skip(':');
AddLabel(name);
Statement();
return;
}
if (constants_list.indexOf('C'+name+'C')>-1) {
Throw('The constant "'+name+'" already exists.');}
var vname = IndexVariable(name,true);
if (tok=='='||tok=='+='||tok=='-='||tok=='*='||tok=='/='||tok=='\\='||tok=='^='||tok=='&=') {
var op = tok;
Next();
var e=Expression();
if (op=='&=') {
op='+=';
} else if (op=='\\=') {
op='//=';
} else if (op=='^=') {
curop+=vname+'=Math.pow('+vname+', '+e+');\n';
return;
}
curop+=vname+' '+op+' ('+e+');\n';
} else {
Throw('Expected "=" or "x=" found "' + tok + '"\n\n(assuming assignment to a variable; could be a case of a misspelled keyword)');
}
}
}
function Compile() {
NewOp();
while (tok != '') {
for (;;) {
// Implement line numbers.
if (tok.match(/^[0-9]+$/)) {
AddLabel(tok);
Next();
}
Statement();
while (tok == ':') {
Next();
Statement();
}
if (tok == '') {
break;
}
SkipEndOfStatement();
}
if (sub_check!=0) {throw(sub_check + ' missing "END SUB".')};
if (fn_check!=0) {throw(fn_check + ' missing "END FUNCTION".')};
}
// Check for matching flow control.
if (flow.length != 0) {
var f = flow.pop();
Throw('Unmatched ' + f[0]);
}
// Implicit End.
NewOp();
curop += 'End();';
NewOp();
// Align to 8.
Align(8);
// Allocate stack.
stack = Allocate(STACK_SIZE);
sp = stack;
bp = sp;
var total = '';
total += 'var buffer = new ArrayBuffer(' +
allocated + ' + ' + DYNAMIC_HEAP_SIZE + ');\n';
for (var i in SIMPLE_TYPE_INFO) {
var info = SIMPLE_TYPE_INFO[i];
if (i == 'string') {
total += 'var str = [];\n';
} else {
total += 'var ' + info.view +
' = new ' + info.array + '(buffer);\n';
}
}
total += var_decls;
total += 'for (var j = 0; j < ops.length; ++j) {\n';
if (debugging_mode) {
total += ' console.info("L" + j + ":\\n" + ops[j]);\n';
}
total += ' ops[j] = eval("(function() {\\n" + ops[j] + "})\\n");\n';
total += '}\n';
if (debugging_mode) {
console.info(total);
}
eval(total);
}
var viewport_x, viewport_y;
var viewport_w, viewport_h;
function Resize() {
if (from_tag) {canvas.width=window.innerWidth;canvas.height=window.innerHeight;}
canvas.width-=2;canvas.height-=2;
var raspect = canvas.width / canvas.height;
var aspect = display.width / (display.height * screen_aspect);
if (raspect > aspect) {
viewport_w = Math.floor(
display.width * canvas.height / (display.height * screen_aspect));
viewport_h = canvas.height;
viewport_x = Math.floor((canvas.width - viewport_w) / 2);
viewport_y = 0;
} else {
viewport_w = canvas.width;
viewport_h = Math.floor(
(display.height * screen_aspect) * canvas.width / display.width);
viewport_x = 0;
viewport_y = Math.floor((canvas.height - viewport_h) / 2);
}
}
function Render() {
if (!canvas) {
return;
}
var scale_ctx = scale_canvas.getContext('2d');
scale_ctx.fillStyle = '#000';
scale_ctx.fillRect(0, 0, scale_canvas.width, scale_canvas.height);
scale_ctx.putImageData(display, 0, 0);
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#aaaaaa'; // cjv
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.imageSmoothingQuality = 'high';
ctx.imageSmoothingEnabled = false;
ctx.drawImage(scale_canvas, viewport_x, viewport_y,
viewport_w, viewport_h);
requestAnimationFrame(Render);
}
function RegularKey(n) {
keys.push(String.fromCharCode(n));
}
function ExtendedKey(n) {
keys.push(String.fromCharCode(0) + String.fromCharCode(n));
}
function InitEvents() {
const SIMPLE_KEYMAP = {
// BACKSPACE, ENTER, ESCAPE
8: { regular: 8 }, 13: { regular: 13 }, 27: { regular: 27 },
// INS, DEL
45: { regular: 82 }, 46: { regular: 83 },
// LEFT, RIGHT
37: { extended: 75 }, 39: { extended: 77 },
// UP, DOWN
38: { extended: 72 }, 40: { extended: 80 },
// PGUP, PGDN
33: { extended: 73 }, 34: { extended: 81 },
// HOME, END
36: { extended: 71 }, 35: { extended: 79 },
};
if (!canvas) {
return;
}
Resize();
if (from_tag) {
window.addEventListener('resize', Resize, false);
}
window.addEventListener('keyup',function(e){
keyState[e.keyCode || e.which] = false;
keyPressed = 0;
},false);
window.addEventListener('keydown', function(e) {
keyPressed = e.keyCode || e.which;
keyState[keyPressed] = true;
if (SleepUntilKey==1) {SleepUntilKey=0;}
if (e.keyCode >= 112 && e.keyCode <= 123) {
// F1 - F10
if (e.altKey) {
ExtendedKey(e.keyCode - 112 + 104);
} else if (e.ctrlKey) {
ExtendedKey(e.keyCode - 112 + 94);
} else if (e.shiftKey) {
ExtendedKey(e.keyCode - 112 + 84);
} else {
ExtendedKey(e.keyCode - 112 + 59);
}
} else if (e.keyCode == 9) {
// TAB, Shift-TAB
if (e.shiftKey) {
RegularKey(15);
} else {
RegularKey(9);
}
} else if (SIMPLE_KEYMAP[e.keyCode]) {
if (SIMPLE_KEYMAP[e.keyCode].regular) {
RegularKey(SIMPLE_KEYMAP[e.keyCode].regular);
} else {
ExtendedKey(SIMPLE_KEYMAP[e.keyCode].extended);
}
} else if (e.ctrlKey && e.keyCode >= 65 && e.keyCode <= 90) {
// Ctrl-A to Ctrl-Z
RegularKey(e.keyCode - 65 + 1);
} else if (e.altKey) {
const ch = String.fromCharCode(e.keyCode);
const row1 = '1234567890-='.indexOf(ch);
const row2 = 'QWERTYUIOP'.indexOf(ch);
const row3 = 'ASDFGHJKL'.indexOf(ch);
const row4 = 'ZXCVBNM'.indexOf(ch);
if (row1 >= 0) {
ExtendedKey(row1 + 120);
} else if (row2 >= 0) {
ExtendedKey(row2 + 16);
} else if (row3 >= 0) {
ExtendedKey(row3 + 30);
} else if (row4 >= 0) {
ExtendedKey(row4 + 44);
}
} else {
const code = e.key.charCodeAt(0);
if (e.key.length == 1 && code >= 32 && code <= 126) {
RegularKey(code);
}
}
}, false);
canvas.addEventListener('mousemove', function(e) {
// TODO: Generalize for non-fullscreen.
//var rect = canvas.getBoundingClientRect();
var rect = {left: 0, top: 0};
mouse_x = Math.floor(
(e.clientX - rect.left - viewport_x) * display.width / viewport_w);
mouse_y = Math.floor(
(e.clientY - rect.top - viewport_y) * display.height / viewport_h);
}, false);
canvas.addEventListener('touchmove', function(e) {
var touch = e.touches.item(0);
const evt = new Event('mousemove');
evt.clientX = touch.clientX;
evt.clientY = touch.clientY;
canvas.dispatchEvent(evt);
}, false);
canvas.addEventListener('mousedown', function(e) {
if (SleepUntilKey==1) {SleepUntilKey=0;}
var e = e || window.event;
if (e.button == 0) {mouse_buttons = -1;}
}, false);
canvas.addEventListener('touchstart', function(e) {
canvas.dispatchEvent(new Event('mousedown'));
}, false);
canvas.addEventListener('mouseup', function(e) {
mouse_buttons = 0;
}, false);
canvas.addEventListener('mouseleave', function(e) {
mouse_buttons = 0;
}, false);
canvas.addEventListener('mouseover', function(e) {
mouse_buttons = e.buttons;
}, false);
canvas.addEventListener('touchend', function(e) {
canvas.dispatchEvent(new Event('mouseup'));
}, false)
// TODO: Implement Mouse Wheel!
canvas.addEventListener('wheel', function(e)
{
if (event.deltaY < 0) {mouse_wheel = mouse_wheel - 1;}
else if (event.deltaY > 0) {mouse_wheel = mouse_wheel + 1;}
});
// TODO: Implement Mouse Clip!
}
function Run() {
var speed=10000001-0;
for (;;) {
for (var i=0;i
Subscribe to:
Post Comments (Atom)
I don't know if you want feedback but this is what i see using Chrome on my Windows PC.
ReplyDeleteFirstly there is a pop-up (white text on black background) "aeonsnauguries.blogspot.com says
=== end of program has been reached ==="
Clearing that there is a short start to a normal blog post "Monday, April 21, 2025
A Little expriment. If this works well enough I might be able to get some fun little applets on the blog."
Below that is a little harder to describe but basically the left side of the blog column is taken up by a big grey rectangle, while to the right large blocky text stretches over the right side including over the widgets for followers and blog archive with the text "Just a test
I've been exploring code oprtons for posts
Here's some random numbers
26 27 42"
The good news is the numbers change every time I reload the page, so they are probably random.
Screenshot of your post from my computer is here. https://drive.google.com/file/d/1hnqbFajuxqLQV-UKyjqIav4o2THVD5Oj/view?usp=drive_link
Thanks for the feedback. Yup the numbers should be random. I probably should have at least included a "click me" interface to the applet so it wasn't so jarring. I just have to figure out how to shove the generated scree image into a frame, so they don't overflow the design. Thank You again.
Delete