Skip to content

Instantly share code, notes, and snippets.

@jonasbits
Last active December 26, 2015 02:28
Show Gist options
  • Save jonasbits/7078237 to your computer and use it in GitHub Desktop.
Save jonasbits/7078237 to your computer and use it in GitHub Desktop.
I want to make this forth simulator take bitcoin OP commands
/**
@preserve
JS-Forth
http://www.forthfreak.net/index.cgi?jsforth
Licensed under th GNU GPL.
Disclaimer: JS-Forth is delivered as-is. No warranties,
implicit or explicit, towards its function, usability, fitness
for any purpose are given. It is distributed for educative
purposes, you may study it to your hearts delight. Should
you plan to execute JS-Forth on any computer, you declare
to not hold the programmer liable in any way for any damage
JS-Forth may cause, be it to that computer, peripherals, or any
other object in the range of several thousand kilometers, or
more. The person initiating execution of JS-Forth is the one
carrying sole responsibility for all and any damage resulting
from this action. Also, you do not hold the programmer liable
for any damage resulting from the study of JS-Forth. Please
do not stick your tongue into the power supply of the computer
which is running JS-Forth.
By opening JS-Forth for reading or execution, you make a full
statement that you have read and understood all of the above
disclaimer, and proceed willingly, volunteerily, and of your
own choice on your own risk and responsability.
Having said that, I can assure you that JS-Forth has not been
written to perform any malicious action on your computer or
anyone elses. I run Js-Forth frequently, and no damage has
occured from doing so, though no extensive testing has been
done on it as a whole yet. Those parts which work do so in a
pretty stable manner. A major version jump to v0.01 may be imminent.
*/
var version = "0" ;
var subversion = "5200804171342" ;
var title = "## JS-Forth " + version + "." + subversion + " ##" ;
// --------------------------------------------- vars you may wish to customize ---------------------------------------------------
var memend = 0x100000 ; // memory allocated to jsforth (1 megacells is more than plenty)
var maxcookies = 25 // number of disk sectors. >4 may be unsafe.
var cookiebasename = "jsrepl-jsforth" ; // cookie name for saved blocks (blk number gets appended)
var cookieexpirationdate = Date(Date.now() + 5 * 365 * 24 * 60 * 60 * 1000) ; // the date your hard disk will get erased.
var infolines = 1000 ; // backscroll buffer size of info screen
var paddistance = 512 ; // space between here and pad.
var padsize = 512 ; // remaining space above pad until dictionary overflow error
var maxbufs = 2 ; // number of buffers. works with any between 1 ... maxmem
// default=2, more may be useful if working with many remote blocks
var blocktimeout = 5000 ; // file i/o error if request not completed with this time (ms)
// --------------------------------------------------------------------------------------------------------------------------------
// --- character codes
var backspace = 8 ;
var tab = 9 ;
var carriagereturn = 13 ;
var esc = 27 ;
var bl = 32 ;
var suspended = -1 ; // reason for suspending interpreter (event type)
// -1: never started (helps source locator in see)
var dp = 0 ; // dictionary pointer
var catchframe = 0 ; // for catch/throw
var wc = 0 ; // header count
var inbuf = new Array() ; // accumulated input characters
var linelen = 80 ; // main screen
var lines = 30 ;
var linelen2 = 55 ; // info screen
var lines2 = lines ;
var screensize = lines * linelen ;
var tibsize = linelen + 1 ;
var dictionaryfull = memend - (paddistance + padsize) ;
// heap memory tracking
var usedchunk = new Array() ;
var freechunk = new Array() ;
var heapend = memend ;
// word header bit masks
var immediate = 1 ;
var smudgebit = 2 ;
var precedencebit = immediate ;
var s = new Array(); // data stack
var r = new Array(); // return stack
var m = new Array(); // main memory
var h = new Array(); // headers
var hf = new Array(); // header flags (precendence bit, hide/reveal)
var x = new Array(); // execution tokens
var t = new Array(); // word type - accelerated execution because no
var sourceid = new Array(); // nested loads/evaluate stack previous source id here
// conditional branching to the corresponding
// code for next per wordtype. this array contains
// the proper next to use. this should also
// simplify does>
h[0] = "" ; // in case header 0 gets accidently requested
var f = new Array(); // float stack
var ip; // forth vm instruction pointer
var w; // forth vm word register
var sp = 0; // forth vm parameter stack pointer
var rp = 0; // forth vm return stack pointer
var tos; // stack cache
var ftos; // float stack cache
// constants for standard compliance bit masks
// a combination of those are written to the description of each word
// through variable COMPLIANCE, subsets of provided words are masked
var standard = new Array() ;
// standard selection and vocabularies share the same mechanism. therefore,
// using both concepts is a bit of a mix here now.
// standards and vocabularies use bit masks
var nextvocabulary = 1 ; var uncertain = nextvocabulary ; standard[uncertain] = " possibly other, need to look that up first" ;
nextvocabulary <<= 1 ; var fig = nextvocabulary ; standard[fig] = "fig" ;
nextvocabulary <<= 1 ; var f79 = nextvocabulary ; standard[f79] = "f79" ;
nextvocabulary <<= 1 ; var f83 = nextvocabulary ; standard[f83] = "f83" ;
nextvocabulary <<= 1 ; var ans = nextvocabulary ; standard[ans] = "dpans94" ;
nextvocabulary <<= 1 ; var foerthchen= nextvocabulary ; standard[foerthchen]= "FOeRTHchen" ;
nextvocabulary <<= 1 ; var jsf = nextvocabulary ; standard[jsf] = "JS-Forth" ;
var higheststandard = nextvocabulary ;
var any = ans | f83 | f79 | fig | jsf ; // but not foerthchen
// --- no more standards, vocabularies follow ---
nextvocabulary <<= 1 ; var only = nextvocabulary ;
nextvocabulary <<= 1 ; var forth = nextvocabulary ;
nextvocabulary <<= 1 ; var hidden = nextvocabulary ;
nextvocabulary <<= 1 ; var teststuff = nextvocabulary ;
var lastsystemvocabulary = nextvocabulary ;
var vocstack = new Array() ; // top element is in m[context]
var vocname = new Array() ; // contains xt of all vocs
function printvocname(n) {
var temp = 0 ;
for (var i=only ; i != 0x40000000 ; i <<=1 ) {
if (i == n) {
type(h[vocname[temp]] + " ") ;
break ;
}
temp++ ;
}
}
function jscomma(n) { m[dp++] = n ; return (dp-1) ;}
function jshiallot0(n) { // heap (buffers, allocate)
for (var i=n ; i ; i--) m[heapend++] = 0 ;
return (heapend-n) ;
}
// variables, shared between javascript and forth:
// addressed by m[varname] from javascript, define a constant
// with value of address for access from forth.
var casesensitive = jscomma(0) ; // switch case sensitive/insensitive dictionary search
var debugging = jscomma(0) ; // get spilled with output on info display
var warnings = jscomma(-1) ; // meant to disable javascript warnings, but hides only error messages
var compliance = jscomma(jsf) ; // cause find, words to scope only those words complying with the selected standard
var fittype = jscomma(0) ; // ALLOCATE chunk matching: 0: first, other: best fit
var outfile = jscomma(-1) ; // switch between output routines:
// -1 : fast terminal
// -2 : slow terminal
// >=0 : output to consecutive blocks ( not implemented )
var blk = jscomma(-1) ; // currently accessed block, as set by load
var scr = jscomma(0) ; // last block accessed through list or user tools
var context = jscomma(forth) ; // first searched vocabulary on vocabulary stack
var current = jscomma(forth) ; // the vocabulary compiled to
var lastxt = jscomma(0) ; // contains execution token of most recently compiled word
var base = jscomma(10) ; // radix for i/o number conversion
var state = jscomma(0) ; // switch interpret/compile
var innerloop = jscomma(0) ; // compile time helper variable for loops
var innercase = jscomma(0) ; // of counter for inner case
var span = jscomma(0) ; // obsolete -- expect stores string len in here
var toin = jscomma(0) ; // input buffer handling
var hashtib = jscomma(0) ; // obsolescent - contains # chars in tib
var tib = jshiallot0(tibsize) // input buffer
var parsebuf ; // usually address of tib, but can be block address
var parsebuflen ; // number of chars in parse buffer
// ----------------------------------------------- mass memory buffers ---------------------------------------------
var nextbuf = 0 ; // index of next buffer to use
var buf = new Array() ; // buffer addresses
var bufdirty = new Array() ; // buffer dirty flag
var bufblk = new Array() ; // block in this buf, or -1
var blockstat = new Array() // -1: indexed by blk, gives -1 for unbuffered, or, if buffered, buffer id
// ----- data storage for descriptions, stack effects -----
// also trying to use these for vocabularies
// "standard" is printed along with help. As this information is supplied
// anyway, the compiler could use it, by making sure only words which belong
// to a user specified standard are used, or printing warning otherwise.
var ds = new Array(); // bitmask for compliancy and vocs
var dse = new Array(); // stack effect, text
var lineofspaces = "" ;
for ( var i=0 ; i<linelen ; i++ ) lineofspaces += " " ;
function describe(string1,bitmask) {
dse[wc] = string1 ;
ds[wc] = 0 | m[current] ; if (bitmask) ds[wc] = bitmask | m[current];
}
// =================================================================================================
// dumb terminal emulator
// =================================================================================================
// ---- infos screen ----
function printinfos() {
// Nothing.
}
function info(string) {
// Nothing.
}
function debug(string) { if (m[debugging]) info(string) ; }
// ---- interactive terminal screen ----
// THIS SHOULD BE REPLACED BY THE DESIRED PRINTING FUNCTION.
function _print(str) {
document.terminal.dialog.value += str;
}
function type(string) {
_print(string);
}
var write = type;
function cr() {
_print("\n");
}
function cls() {
// Nothing.
}
function backspaces(n) {
// Nothing.
}
function emit(asc) { type(String.fromCharCode(asc)); }
var querytype = type;
// =================================================================================================
// primitives constructor
// =================================================================================================
var src = new Array() ;
// -2: script file
// -1: interactive console
// 0... blk*1024+charpos
function from() {
if (suspended) return -2 ;
if (m[blk] >= 0) return m[blk]*1024+m[toin] ;
return -1 ;
}
function newheader(name,flags) { // wc = word count
h[++wc] = name ; // header name
src[wc] = from() ;
hf[wc] = flags ; // immediate/reveal
x[wc] = dp ; // pointer to word body (was: xt)
m[lastxt] = wc ; // last
ds[wc] = any | foerthchen | m[current] ; // new words standard compliance
dse[wc] = "" ; // new word stack effect
debug("compiling: " + name);
}
function nextprimitive() { x[w]() ; }
function nexthilevel() { w = x[w] ; x[m[w]]() ; }
function nextconstant() { s[++sp]=tos ; tos=m[x[w]+1] ; }
function nextvariable() { s[++sp]=tos ; tos=x[w]+1 ; }
// function nexthilevel() { r[++rp] = ip ; ip = x[w]+1 ; } // slower ...
// there's a dovocabulary further below, and a dodoes
function primitive(name,code,flags) {
newheader(name,flags|smudgebit) ;
x[wc] = code ;
t[wc] = nextprimitive ;
return wc ;
}
function headerless() { h[wc] = "" ; }
// =================================================================================================
// misc helper words
// =================================================================================================
definitions(hidden) ;
function pack(a,n) {
w = "" ;
for ( var i=n ; i; i--) w += String.fromCharCode(m[a++]) ;
return w;
}
function forthpack() { tos=pack(s[sp--],tos) ; }
var x_pack=primitive("pack",forthpack) ;
describe("a n -- x",jsf) ;
function unpackstring(string,address) { // returns len
var stringlen = string.length ;
var destaddr = address + stringlen ;
for (var i=stringlen; i; m[--destaddr]=string.charCodeAt(--i) ) {} ;
return stringlen ;
}
// unpack packed string x to address, return number of characters
// can reuse the function above
function unpack() { // ( x a -- n )
var string = s[sp--] ; // string
w = string.length ; // string len
tos += w ; // last dest address + 1
for (var i=w; i; m[--tos]=string.charCodeAt(--i) ) {} ;
tos = w ;
}
var x_unpack = primitive("unpack",unpack) ;
describe("x a -- n",jsf) ;
function definitions(vocabulary) { m[current] = vocabulary ; }
definitions(forth) ;
function forthstackeffect() { // ( xt -- a n )
s[++sp] = dp ;
if (dse[tos]) {
tos = unpackstring("( " + dse[tos] + " )",dp) ;
} else {
tos = 0 ;
}
}
primitive("stackeffect",forthstackeffect) ;
describe("xt -- a n",jsf) ;
definitions(hidden)
function forthstorestackeffect() { // ( a n -- )
forthpack() ;
dse[m[lastxt]] = tos ;
tos = s[sp--]
}
var x_storestackeffect = primitive("stackeffect!",forthstorestackeffect) ;
describe("a n --",jsf) ;
definitions(forth)
function forthinfo() { // ( a n -- ) info
info(pack(s[sp--],tos)) ;
tos = m[sp--] ;
}
primitive("info",forthinfo) ;
describe("a n --",jsf) ;
var clock ;
function forthstartclock() {
clock = new Date().getTime();
}
primitive("startclock",forthstartclock) ;
describe("--",jsf) ;
function forthelapsed() {
w = new Date().getTime();
s[++sp] = tos ;
tos = w - clock ;
}
primitive("elapsed",forthelapsed) ;
describe("-- u",jsf) ;
// ----- multi standard selection -----
definitions(forth) ;
function forthfig() { m[compliance] = fig ; }
primitive("fig",forthfig) ;
describe("--",jsf) ;
function forthfoerthchen() { m[compliance] = foerthchen ; }
primitive("foerthchen",forthfoerthchen) ;
describe("--",jsf) ;
function forthf79() { m[compliance] = f79 ; }
primitive("f79",forthf79) ;
describe("--",jsf) ;
function forthf83() { m[compliance] = f83 ; }
primitive("f83",forthf83) ;
describe("--",f83|jsf) ;
function forthans() { m[compliance] = ans ; }
primitive("ans",forthans) ;
describe("--",jsf) ;
function forthjsforth() { m[compliance] = jsf ; }
primitive("jsf",forthjsforth) ;
describe("--",any|foerthchen) ;
// =================================================================================================
// virtual machine
// =================================================================================================
definitions(hidden) ;
function forthnest() { r[++rp] = ip ; ip = ++w ; }
var x_nest=primitive("(nest)",forthnest) ;
describe("--",jsf) ;
definitions(forth) ;
function forthunnest() { ip = r[rp--] ; }
var x_unnest=primitive("exit",forthunnest) ;
describe("--",any) ;
// =================================================================================================
// catch, throw
// =================================================================================================
var customerror = new Array() ;
var systemerror = new Array() ;
systemerror[1] = "aborted" ;
systemerror[2] = "aborted" ;
systemerror[3] = "stack overflow" ;
systemerror[4] = "stack underflow" ;
systemerror[5] = "return stack overflow" ;
systemerror[6] = "return stack underflow" ;
systemerror[7] = "do loops nested too deeply" ;
systemerror[8] = "dictionary overflow" ;
systemerror[9] = "invalid memory address" ;
systemerror[10] = "division by zero" ;
systemerror[11] = "result out of range" ;
systemerror[12] = "argument type mismatch" ;
systemerror[13] = "word not found" ;
systemerror[14] = "use only during compilation" ;
systemerror[15] = "invalid forget" ;
systemerror[16] = "attempt to use zero-length string as name" ;
systemerror[17] = "pictured numeric ouput string overflow" ;
systemerror[18] = "pictured numeric ouput string overflow" ;
systemerror[19] = "word name too long" ;
systemerror[20] = "write to a read-only location" ;
systemerror[21] = "unsupported operation" ;
systemerror[22] = "unstructured" ;
systemerror[23] = "address alignment exception" ;
systemerror[24] = "invalid numeric argument" ;
systemerror[25] = "return stack imbalance" ;
systemerror[26] = "loop parameters unavailable" ;
systemerror[27] = "invalid recursion" ;
systemerror[28] = "user interrupt" ;
systemerror[29] = "compiler nesting" ;
systemerror[30] = "obsolescent feature" ;
systemerror[31] = ">BODY used on non-CREATEd definition" ;
systemerror[32] = "invalid name argument" ;
systemerror[33] = "Block read exception" ;
systemerror[34] = "Block write exception" ;
systemerror[35] = "Invalid block number" ;
systemerror[36] = "Invalid file position" ;
systemerror[37] = "File I/O exception" ;
systemerror[38] = "File not found" ;
// additional jsforth error messages:
systemerror[64] = "use only while interpreting" ;
systemerror[65] = "executed BODY> on a non-body address" ;
systemerror[66] = "unstructured" ; // message gets overwritten for more detail
systemerror[67] = "TO must be used on a VALUE" ;
systemerror[68] = "JavaScript boo, mostly the result of uninitialized memory access" ;
systemerror[69] = "Too many vocabularies" ;
systemerror[70] = "No cookie by that name found" ;
systemerror[71] = "Can't write to read-only block" ;
systemerror[72] = "Invalid memory region specifier, or heap corrupted" ;
function errordialog(x) {
if (x < 0) {
if (systemerror[-x]) return ("error(" + x + "): " + systemerror[-x]) ;
return ("error #" + x) ;
}
if (customerror[x]) return ("error: " + customerror[x]) ;
return ("error #" + x) ;
}
// THIS SHOULD BE REPLACED BY THE DESIRED ERROR FUNCTION.
function _error(str) {
info(str);
}
// throw without catch frame - top level error handler
function exception(x) {
var word;
if (m[blk]>=0) {
var temp = m[toin] % 64 ;
word = pack(parsebuf + m[toin] - temp,temp) ;
} else {
word = pack(parsebuf,m[toin]) ;
}
_error(word + ': ' + errordialog(x));
// just calling the virtual machine won't do, as that would require more and more javascript return stack.
// stopping the interpreter, and have it restart with a one-time event at the warm start point solves this.
debug("issuing timed event 'warmstart vm in 1 ms'") ;
suspended = warm ;
setTimeout(function() { virtualmachine(warm) ; }, 1) ;
tos = s[sp--] ;
}
definitions(hidden) ;
function forththrow0() {
catchframe = r[rp] ;
sp = r[--rp] ;
ip = r[--rp] ;
rp-- ;
tos = 0 ;
}
var brthrow0 = dp
m[dp++] = primitive("throw0",forththrow0) ;
definitions(forth) ;
function forthcatch() {
r[++rp] = ip ;
r[++rp] = sp ;
r[++rp] = catchframe ;
catchframe = rp ;
r[++rp] = brthrow0 ;
forthexecute() ;
}
var x_catch = primitive("catch",forthcatch) ;
describe("xn ... x0 a -- xn ... x0 n",ans|jsf) ;
function throwerror(x) {
if (catchframe) {
tos = x
rp = catchframe ;
catchframe = r[rp--] ;
sp = r[rp--] ;
ip = r[rp--] ;
} else {
exception(x) ;
}
}
function forththrow() {
if (tos != 0) {
throwerror(tos) ;
} else {
tos = s[sp--] ;
}
}
var x_throw = primitive("throw",forththrow) ;
describe("n --",ans|jsf|f83) ;
function forthnewerror() {
if (tos<0) {
systemerror[-tos] = pack(s[sp-1],s[sp]) ;
} else {
customerror[tos] = pack(s[sp-1],s[sp]) ;
}
sp -= 2 ;
tos = s[sp--] ;
}
primitive("newerror",forthnewerror) ;
describe("a n1 n2 --",jsf) ;
// =================================================================================================
// run time words
// =================================================================================================
definitions(hidden) ;
function forthdolit() { s[++sp]=tos ; tos=m[ip++] ; }
var x_lit=primitive("(lit)",forthdolit) ;
function forthbrsquote() { s[++sp]=tos ; tos=m[ip++] ; s[++sp]=ip ; ip+=tos ; }
var x_brsquote=primitive('(s")',forthbrsquote) ;
function forthbrcquote() { s[++sp]=tos ; tos=ip++ ; ip += m[tos] }
var x_brcquote=primitive('(c")',forthbrcquote) ;
function forthbrdotquote() {
forthbrsquote() ;
forthpack() ;
type(tos) ;
tos=s[sp--] ;
}
var x_brdotquote=primitive('(.")',forthbrdotquote) ;
function forthdovar() { s[++sp] = tos ; tos = ++w ; }
var x_dovar=primitive("(var)",forthdovar) ;
function forthdoconst() { s[++sp]=tos ; tos=m[++w] ; }
var x_doconst = primitive("(const)",forthdoconst) ;
var x_dovalue = primitive("(value)",forthdoconst) ;
function forthdofconst() { f.push(ftos) ; ; ftos = m[++w] ; }
var x_dofconst = primitive("(fconst)",forthdofconst) ;
// function forthdodefer() { ip=++w ; }
// branch 1 works as nop, branch -1 is infinite loop
function forthbranch() { ip+=m[ip] ; }
var x_branch=primitive("(branch)",forthbranch) ;
function forth0branch() {
if (tos) {
ip++ ;
} else {
ip+=m[ip] ;
}
tos=s[sp--] ;
}
var x_0branch=primitive("(0branch)",forth0branch) ;
function forthwarminit() { // not for interactive use
tos = r[rp] ; rp = 0 ; r[rp+1] = 0 ; r[rp] = tos ;
tos = 0 ; sp = 0 ; s[sp+1] = 0 ; s[sp] = tos ;
ftos = 0 ;
for ( ; f.length ; f.pop() ) ;
catchframe = 0 ;
m[state] = 0 ;
m[innerloop] = 0 ;
m[innercase] = 0 ;
m[blk] = -1 ;
m[outfile] = -1 ;
for ( ; inbuf.length ; inbuf.pop() ) ;
}
var x_warminit = primitive("warminit",forthwarminit) ;
function forthbrabortquote() {
if (tos) {
forthbrsquote() ;
forthpack() ;
systemerror[2] = tos ;
throwerror(-2) ;
} else {
tos = s[sp--] ;
ip += m[ip]+1 ;
}
}
var x_brabortquote = primitive('(abort")',forthbrabortquote) ;
function forthbrto() {
m[m[ip++]] = tos ;
tos = s[sp--] ;
}
var x_brto = primitive("(to)",forthbrto) ;
// --- not portable: output packed string literal ---
function jsdotquote() { type(m[ip++])} ;
var dotquote = primitive("",jsdotquote) ;
// =================================================================================================
// stack operators
// =================================================================================================
definitions(forth) ;
function forthdup() { s[++sp] = tos ; } // dup
var x_dup=primitive("dup",forthdup) ;
describe("x -- x x",any|foerthchen) ;
function forthqdup() { if (tos) s[++sp]=tos ; } // ?dup
var x_qdup=primitive("?dup",forthqdup) ;
describe("x -- 0 | x x",any) ;
function forthdrop() { tos = s[sp--] ; } // drop
var x_drop=primitive("drop",forthdrop) ;
describe("x --",any|foerthchen) ;
function forthswap() { w = s[sp] ; s[sp] = tos ; tos = w ; } // swap
var x_swap=primitive("swap",forthswap) ;
describe("x1 x2 -- x2 x1",any|foerthchen) ;
function forthover() { s[++sp]= tos ; tos=s[sp-1] ; } // over
var x_over=primitive("over",forthover) ;
describe("x1 x2 -- x1 x2 x1",any) ;
function forthrot() { // rot
w = s[sp] ;
s[sp] = tos ;
tos = s[sp-1] ;
s[sp-1] = w ;
}
var x_rot = primitive("rot",forthrot) ;
describe("x1 x2 x3 -- x2 x3 x1",any) ;
function forthminrot() { // -rot
w = s[sp-1] ;
s[sp-1] = tos ;
tos = s[sp] ;
s[sp] = w ;
}
primitive("-rot",forthminrot) ;
describe("x1 x2 x3 -- x3 x1 x2",jsf) ;
function forthtuck() { w = s[sp] ; s[sp] = tos ; s[++sp] = w ; }
var x_tuck = primitive("tuck",forthtuck) ; // tuck
describe("x1 x2 -- x2 x1 x2",ans|jsf) ;
function forthnip() { sp-- ; } // nip
var x_nip=primitive("nip",forthnip) ;
describe("x1 x2 -- x2",ans|jsf) ;
function forth2dup() { s[++sp]=tos ; s[++sp]=s[sp-2] ; } // 2dup
var x_2dup=primitive("2dup",forth2dup) ;
describe("x1 x2 -- x1 x2 x1 x2",any) ;
function forth2drop() { sp-- ; tos=s[sp--] ; } // 2drop
var x_2drop=primitive("2drop",forth2drop) ;
describe("x1 x2 --",any) ;
function forth2swap() { // 2swap
w = s[sp-1] ;
s[sp-1] = tos ;
tos = w ;
w = s[sp-2] ;
s[sp-2] = s[sp] ;
s[sp] = w ;
}
primitive("2swap",forth2swap) ;
describe("x1 x2 x3 x4 -- x3 x4 x1 x2",any) ;
function forth2over() { // 2over
s[++sp] = tos ;
tos = s[sp-3] ;
s[++sp] = tos ;
tos = s[sp-3] ;
}
primitive("2over",forth2over) ;
describe("x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2",any) ;
function forthmin() { tos = Math.min(s[sp--],tos) } // min
var x_min = primitive("min",forthmin) ;
describe("n1 n2 -- n3",any)
function forthmax() { tos = Math.max(s[sp--],tos) } // max
primitive("max",forthmax) ;
describe("n1 n2 -- n3",any)
function forthtor() { r[++rp] = tos ; tos = s[sp--] ; } // >r
var x_tor=primitive(">r",forthtor) ;
describe("x --",any|foerthchen)
function forthrfrom() { s[++sp] = tos ; tos = r[rp--] ; } // r>
var x_rfrom=primitive("r>",forthrfrom) ;
describe("-- x",any|foerthchen)
function forthrfetch() { s[++sp] = tos ; tos = r[rp] ; } // r@
var x_rfetch=primitive("r@",forthrfetch) ;
describe("-- x",any)
function forthrdrop() { rp-- ; } // rdrop
var x_rdrop=primitive("rdrop",forthrdrop) ;
describe("-- x",jsf)
function forth2tor() { // 2>r
r[++rp] = s[sp--] ;
r[++rp] = tos ;
tos = s[sp--] ;
}
var x_2tor=primitive("2>r",forth2tor) ;
describe("x1 x2 --",ans|jsf|uncertain)
function forth2rfrom() { // 2r>
s[++sp] = tos ;
tos = r[rp--] ;
s[++sp] = r[rp--] ;
}
var x_2rfrom=primitive("2r>",forth2rfrom) ;
describe("-- x1 x2",ans|jsf|uncertain)
function forth2rfetch() { // 2r@
s[++sp] = tos ;
tos = r[rp] ;
s[++sp] = r[rp-1] ;
}
var x_2rfetch=primitive("2r@",forth2rfetch) ;
describe("-- x1 x2",ans|jsf|uncertain)
function forthdepth() { s[++sp]=tos ; tos=sp-1 ; } // depth
var x_depth=primitive("depth",forthdepth) ;
describe("-- n",ans|f83|jsf|uncertain) ;
function forthpick() { tos = s[sp-tos] ; } // pick
primitive("pick",forthpick) ;
describe("xu ... x1 x0 u -- xu ... x1 x0 xu",any) ;
function forthroll() { // roll
w = s[sp-tos] ;
for ( ; tos ; --tos ) s[sp-tos] = s[sp-tos+1] ;
sp-- ;
tos = w
}
primitive("roll",forthroll) ;
describe("xu xu-1 ... x0 u -- xu-1 ... x0 xu",any) ;
// =================================================================================================
// memory operators
// =================================================================================================
function forthfetch() { tos = m[tos] ; } // @
var x_fetch=primitive("@",forthfetch) ;
describe("a -- x",any|foerthchen) ;
function forthstore() { m[tos] = s[sp--] ; tos = s[sp--] ; } // !
var x_store=primitive("!",forthstore) ;
describe("x a --",any|foerthchen) ;
function forth2fetch() { s[++sp] = m[tos+1] ; tos = m[tos] ; } // 2@
var x_2fetch=primitive("2@",forth2fetch) ;
describe("a -- d",any) ;
function forth2store() { // 2!
m[tos++] = s[sp--] ;
m[tos] = s[sp--] ;
tos = s[sp--] ;
}
var x_2store=primitive("2!",forth2store) ;
describe("d a --",any) ;
function forthcfetch() { tos = m[tos]&255 ; } // c@
var x_cfetch=primitive("c@",forthcfetch) ;
describe("a -- c",any) ;
function forthcstore() { m[tos] = s[sp--]&255 ; tos = s[sp--] ; } // c!
var x_cstore=primitive("c!",forthcstore) ;
describe("c a --",any) ;
function forthcount() { s[++sp]=tos+1 ; tos=m[tos]&255 ; } // count
var x_count=primitive("count",forthcount) ;
describe("a1 -- a2 c",any) ;
function forthskim() { s[++sp]=tos+1 ; tos=m[tos] ; } // skim
var x_skim=primitive("skim",forthskim) ;
describe("a1 -- a2 x",jsf) ;
function forthexchange() { w = m[tos] ; m[tos] = s[sp--] ; tos = w ; } // exchange
var x_exchange=primitive("exchange",forthexchange) ;
describe("x1 a -- x2",jsf) ;
function forthon() { m[tos] = -1 ; tos = s[sp--] ; } // on
primitive("on",forthon) ;
describe("a --",jsf) ;
function forthoff() { m[tos] = 0 ; tos = s[sp--] ; } // off
var x_off = primitive("off",forthoff) ;
describe("a --",jsf) ;
function forthfill() { // fill
i = s[sp--] ;
var dest=s[sp--]
for ( ; i ; i-- ) m[dest++]=tos ;
tos = s[sp--] ;
}
var x_fill=primitive("fill",forthfill) ;
describe("a u c --",any) ;
function fortherase() { s[++sp] = tos ; tos = 0 ; forthfill() ; }
primitive("erase",fortherase) ;
describe("a u --",any) ;
function forthslashstring() { // /string
w = tos ;
tos = s[sp--] ;
if ( tos < w ) w = tos ;
s[sp] += w ;
tos -= w ;
}
var x_slashstring=primitive("/string",forthslashstring) ;
describe("a1 n1 u -- a2 n2",ans|jsf|uncertain) ;
function noop() { }
primitive("align",noop|immediate) ; // align
describe("--",ans|jsf) ;
primitive("aligned",noop|immediate) ; // aligned
describe("a1 -- a2",ans|jsf)
function forthpad() { s[++sp] = tos ; tos = dp + paddistance ; }
primitive("pad",forthpad) ; // pad
describe("-- a",any) ;
// =================================================================================================
// i/o
// =================================================================================================
var x_cr=primitive("cr",cr) ; // cr
describe("--",any) ;
definitions(forth) ;
function forthspaces() { // spaces
for ( ; tos>linelen ; tos-=linelen ) type(lineofspaces) ;
type(lineofspaces.substring(0,tos)) ;
tos = s[sp--] ;
}
var x_spaces=primitive("spaces",forthspaces) ;
describe("n --",any) ;
definitions(hidden) ;
// --- messages written to dialog screen ---
definitions(forth) ;
function forthspace() { type(" ") ; } // space
var x_space=primitive("space",forthspace) ;
describe("--",any) ;
function forthemit() { emit(tos) ; tos = s[sp--] ; } // emit
var x_emit=primitive("emit",forthemit) ;
describe("c --",any|foerthchen) ;
function forthtype() { // type
forthpack() ;
type(tos) ;
tos = s[sp--] ;
}
var x_type=primitive("type",forthtype) ;
describe("--",any) ;
var x_page= primitive("page",cls) ; // page
describe("--",ans|f83|jsf) ;
primitive("cls",cls) ;
describe("--",jsf) ;
// THIS SHOULD BE REPLACED BY THE DESIRED PROMPTING FUNCTION.
function _prompt() {
// Nothing.
}
function forthprompt() { // prompt
_prompt();
}
var x_prompt=primitive("prompt",forthprompt) ;
describe("--",any) ;
function forthdots() { // .s
s[++sp] = tos;
for (var i=1 ; i < sp ; type(s[++i].toString(m[base]) + " ")) ;
sp-- ;
}
var x_dots = primitive(".s",forthdots) ;
describe("--",any) ;
// read string, delimited by c. return address and len
// updates source
function forthparse() { // parse
var delimiter = tos ;
w = m[toin] + parsebuf ; // parse address
var bufend = parsebuf + parsebuflen ;
var nxtchar = m[w] ;
if (delimiter == bl) {
for ( ; w < bufend ; ) {
if (nxtchar != delimiter) break ;
nxtchar = m[++w] ;
}
}
s[++sp] = w ;
for ( ; w < bufend; ) {
nxtchar = m[w] ;
if (nxtchar == delimiter) break ;
w++ ;
}
tos = w - s[sp] ;
if (nxtchar == delimiter) w++ ;
m[toin] = w - parsebuf ;
}
var x_parse = primitive("parse",forthparse) ;
describe("c -- a n",ans|jsf) ;
definitions(hidden) ;
// key and key? come in two parts:
// part 1 signals to virtual machine to stop execution,
// part 2 will be executed after the input event occured
// the high level key and key? word call both parts, and, at the
// same time, provide the after-event reentry point.
function forthkey1() {
if (!inbuf.length) {
suspended = w ;
_input(function() { virtualmachine(ip) ; }) ;
}
}
var x_key1 = primitive("key1",forthkey1) ;
describe("--",jsf)
function forthkey2() { s[++sp] = tos ; tos = inbuf.shift() ; }
var x_key2 = primitive("key2",forthkey2) ;
describe("-- c",jsf)
function forthkey1query() {
if (!inbuf.length) { // key buffered - no need for event
suspended = w ; // stop interpreter shortly to allow possible key event
setTimeout(function() { virtualmachine(ip) ; }, 0) ; // restart short time later
}
}
var x_key1query = primitive("key1?",forthkey1query) ;
describe("--",jsf)
function forthkey2query() {
s[++sp] = tos ;
tos = 0 ; // assume "no key"
if (inbuf.length) tos-- ; // flag "key available"
}
var x_key2query = primitive("key2?",forthkey2query) ;
describe("-- f",jsf)
// ( bufaddr editaddr nkeys ascii -- bufaddr editaddr nkeys )
function forthacceptprintable() {
w = tos ;
tos = s[sp--] ; // w:asc, tos:n keys to go, s[sp]:editing address, s[sp-1]: buffer start
if (tos>1) {
m[s[sp]] = w ;
s[sp]++ ;
tos-- ;
}
}
// ( bufaddr editaddr nkeys ascii -- bufaddr editaddr nkeys )
function forthacceptescape() {
tos = s[sp--] ; // tos:n keys to go, s[sp]:editing address, s[sp-1]: buffer start
tos += (s[sp] - s[sp-1]) ;
backspaces(s[sp]-s[sp-1]) ;
s[sp] = s[sp-1] ;
}
// ( bufaddr editaddr nkeys ascii -- bufaddr editaddr nkeys )
// attempt internet explorer workaround
function forthacceptbackspace() {
tos = s[sp--]
if (s[sp] > s[sp-1]) {
tos++ ;
s[sp]-- ;
backspaces(1);
}
}
function forthacceptreturn() { sp-- ; tos = 0 }
function forthaccepttab() { tos=bl ; forthacceptprintable() ; }
// ( bufaddr editaddr nkeys ascii -- bufaddr editaddr nkeys )
function forthacceptcontrolchar(ctrlchar) {
if (ctrlchar == esc) { forthacceptescape() ; return ; }
if (ctrlchar == backspace) { forthacceptbackspace() ; return ; }
if (ctrlchar == 17) { forthacceptbackspace() ; return ; } // ctrl-q for IE
if (ctrlchar == carriagereturn) { forthacceptreturn() ; return ; }
if (ctrlchar == tab) { forthaccepttab() ; return ; }
tos = s[sp--] ;
}
function forthdecode() { // ( bufaddr editaddr nkeys ascii -- bufaddr editaddr nkeys )
if (tos<bl) {
forthacceptcontrolchar(tos) ;
} else {
forthacceptprintable(tos) ;
}
debug(s[sp-1] + " " + s[sp] + " " + tos) ;
}
var x_decode = primitive("decode",forthdecode) ;
describe("a1 a2 n1 c -- a1 a3 n2 f",jsf)
definitions(forth) ;
function forthfast() { m[outfile] = -1 ; } ; primitive("fast",forthfast) ;
describe("--",jsf) ;
function forthslow() { m[outfile] = -2 ; } ; primitive("slow",forthslow) ;
describe("--",jsf) ;
function forthsource() {
s[++sp] = tos ;
s[++sp] = parsebuf ;
tos = parsebuflen ;
}
var x_source = primitive("source",forthsource) ;
describe("-- a n",any) ;
function forthstoresource() {
parsebuflen = tos ;
parsebuf = s[sp--] ;
tos = s[sp--] ;
// m[toin] = 0 ;
}
var x_storesource = primitive("!source",forthstoresource) ;
describe("a n --",jsf) ;
definitions(hidden) ;
function forthpushsource() { sourceid.push(m[toin],parsebuf,parsebuflen) ; }
var x_pushsource = primitive("pushsource",forthpushsource) ;
function forthpopsource() {
parsebuflen = sourceid.pop() ;
parsebuf = sourceid.pop() ;
m[toin] = sourceid.pop() ;
}
var x_popsource = primitive("popsource",forthpopsource) ;
// ------------- cookies ------------
var translatedchar = new Array() ; // each ascii requiring translation flags it here
for (i=0 ; i<256 ; i++) translatedchar[i] = "" ; // assume no translation required
translatedchar[0] = "A" ;
translatedchar[9] = "B" ;
translatedchar[10] = "C" ;
translatedchar[13] = "D" ;
translatedchar[32] = "E" ;
translatedchar[37] = "F" ;
translatedchar[59] = "G" ;
var translatechar = new Array(0,9,10,13,32,37,59) ;
function encoded(text) {
var result = "" ;
var asc;
for (i=0 ; i<text.length ; i++) {
asc = text.charCodeAt(i) ;
if (translatedchar[asc]) {
result += ("%" + translatedchar[asc]) ;
} else {
result += text.charAt(i) ;
}
}
return result ;
}
function decoded(text) {
var result = "" ;
var asc;
for (i=0; i<text.length ; i++) {
asc = text.charAt(i) ;
if (asc == "%") asc = String.fromCharCode(translatechar[text.charCodeAt(++i) - 65]) ;
result += asc ;
}
return result ;
}
function setcookie(name, value, domain, expires, path, secure) {
var cook = name + "=" + encoded(value.substr(0,2048)) ;
cook += (domain) ? "; domain=" + domain : "" ;
cook += (expires) ? "; expires=" + expires : "" ;
cook += (path) ? "; path=" + domain : "" ;
cook += (secure) ? "; secure=" + domain : "" ;
document.cookie = cook ;
}
function readcookie(name) {
var cookiebegin = document.cookie.indexOf(name + "=") ;
if (cookiebegin == -1) return null ;
var temp = document.cookie.substr(cookiebegin + name.length + 1) ;
var cookieend = temp.indexOf(";") ;
if (cookieend != -1) return decoded(temp.substr(0,cookieend)) ;
return decoded(temp) ;
}
definitions(forth) ;
function forthsetcookie() {
setcookie((pack(s[sp-2],s[sp-1])),(pack(s[sp],tos))) ;
sp -= 3 ;
tos = s[sp--]
}
primitive("cookie!",forthsetcookie) ;
describe("a1 n1 a2 n2 --",jsf) ;
function forthreadcookie() {
w = readcookie(pack(s[sp-1], s[sp])) ;
if (w) {
s[--sp] = w ;
unpack() ;
} else {
throwerror(-70) ;
}
}
primitive("cookie@",forthreadcookie) ;
describe("a1 n1 a2 -- n2",jsf) ;
// =================================================================================================
// arithmetics
// =================================================================================================
definitions(forth) ;
function forth1plus() { tos++ ; } // 1+
var x_1plus=primitive("1+",forth1plus) ;
describe("x -- x+1",ans|f83|jsf) ;
primitive("cell+",forth1plus) ; // cell+
describe("x -- x+cell",ans|f83|jsf) ;
primitive("char+",forth1plus) ; // char+
describe("x -- x+char",ans|jsf) ;
function forth1minus() { tos-- ; } // 1-
var x_1minus=primitive("1-",forth1minus) ;
describe("x -- x-1",any) ;
primitive("cell-",forth1minus) ; // cell-
describe("x -- x-cell",ans|f83|jsf) ;
function forth2mul() { tos <<= 1 ; } // 2*
var x_2mul=primitive("2*",forth2mul) ;
describe("x1 -- x2",any) ;
function forth2div() { tos >>= 1 ; } // 2/
var x_2div=primitive("2/",forth2div) ;
describe("n1 -- n2",any) ;
function forthplus() { tos += s[sp--] ; } // +
var x_plus=primitive("+",forthplus) ;
describe("x1 x2 -- x1+x2",any|foerthchen) ;
function forthminus() { tos = s[sp--] - tos ; } // -
var x_minus=primitive("-",forthminus) ;
describe("x1 x2 -- x1-x2",any) ;
function forthmul() { tos = (tos*s[sp--]) & 0xffffffff ; } // *
var x_mul=primitive("*",forthmul) ;
describe("x1 x2 -- x1*x2",any|foerthchen) ;
var floorfix = 1 - 1e-16 ;
function forthdiv() { // /
if (tos) {
tos = s[sp--] / tos ;
if (tos<0) tos += floorfix ;
tos = Math.floor(tos) ;
return ;
}
throwerror(-10) ;
}
var x_div=primitive("/",forthdiv)
describe("x1 x2 -- x1/x2",any) ;
function forthstarslash() { // */
if (tos) {
tos = (s[sp--] * s[sp--]) / tos;
if (tos<0) tos += floorfix ;
tos = Math.floor(tos) ;
return ;
}
throwerror(-10) ;
}
var x_starslash = primitive("*/",forthstarslash) ;
describe("x1 x2 x3 -- x1*x2/x3",any) ;
function forthmod() { // mod
if (tos) {
tos= (s[sp--] % tos) ;
return ;
}
throwerror(-10) ;
}
var x_mod=primitive("mod",forthmod) ;
describe("x1 x2 -- x3",any) ;
function forthslashmod() { // /mod
if (tos) {
w = s[sp] % tos ;
tos = s[sp] / tos ;
if (tos<0) tos += floorfix ;
tos = Math.floor(tos) ;
s[sp] = w ;
return ;
}
throwerror(-10) ;
}
var x_slashmod = primitive("/mod",forthslashmod) ;
describe("x1 x2 -- x3 x4",any|foerthchen) ;
function forthstarslashmod() { // */mod
if (tos) {
w = s[sp--] * s[sp] ;
s[sp] = w % tos ;
tos = w / tos ;
if (tos<0) tos += floorfix ;
tos = Math.floor(tos) ;
return ;
}
throwerror(-10) ;
}
var x_starslashmod = primitive("*/mod",forthstarslashmod) ;
describe("x1 x2 x3 -- x4 x5",any) ;
function forthnegate() { tos= -tos ; } // negate
var x_negate=primitive("negate",forthnegate) ;
describe("n -- -n",any) ;
function forthabs() { tos = Math.abs(tos) ; } // abs
var x_abs=primitive("abs",forthabs) ;
describe("n -- u",any) ;
function forthlshift() {
if (tos>31) {
tos=0;
sp--;
} else {
tos = s[sp--] << tos; // lshift
}
}
var x_lshift = primitive("lshift",forthlshift) ;
describe("x1 u --x2",ans|f83|jsf) ;
primitive("<<",forthlshift) ;
describe("x1 u -- x2",jsf) ;
function forthrshift() {
if (tos>31) {
tos=0;
sp--;
} else {
tos = s[sp--] >>> tos ; // rshift
}
}
var x_rshift = primitive("rshift",forthrshift) ;
describe("u1 u2 -- x3",ans|f83|jsf) ;
primitive(">>",forthrshift) ;
describe("u1 u2 -- u3",jsf) ;
function forthplusstore() { m[tos]+=s[sp--] ; tos=s[sp--] ; } // +!
var x_plusstore=primitive("+!",forthplusstore) ;
describe("x a --",any) ;
primitive("cells",noop,immediate)
describe("x1 -- x2",ans|f83|jsf) ;
primitive("chars",noop,immediate) // chars
describe("x1 -- x2",ans|jsf) ;
function forthrange() {
var temp = tos ;
tos = s[sp] ;
s[sp] += temp ;
}
var x_range = primitive("range",forthrange) ;
describe("x n -- x+n x",ans|jsf|f83) ;
// ----- double and mixed len math -----
function forthstod() { // s>d
s[++sp] = tos ;
tos &= 0x80000000 ;
if (tos) tos = -1 ;
}
var x_stod = primitive("s>d",forthstod) ;
describe("x -- d",any) ;
function forthdnegate() { // dnegate
tos = -tos
s[sp] = -(s[sp]) ;
if (s[sp]) tos-- ;
}
primitive("dnegate",forthdnegate) ;
describe("d1 -- -d1",any) ;
function forthdabs() { // dabs
if (tos<0) {
tos = -tos
s[sp] = -(s[sp]) ;
if (s[sp]) tos--;
}
}
var x_dabs = primitive("dabs",forthdabs)
describe("d -- ud",any) ;
function forthdplus() { // d+
if (tos<0) tos += 0x100000000 ;
var low2 = s[sp--] ; if (low2<0) low2 += 0x100000000 ;
var high1 = s[sp--] ; if (high1<0) high1 += 0x100000000 ;
var low1 = s[sp] ; if (low1<0) low1 += 0x100000000 ;
tos += high1 ;
w = low1+low2 ;
if (w > 0x100000000) { // detect carry
w &= 0xffffffff ;
tos++ ; // apply carry
}
s[sp] = w ;
tos &= 0xffffffff ;
}
var x_dplus = primitive("d+",forthdplus)
describe("d1 d2 -- d1+d2",any) ;
function forthummul() { // ( u1 u2 -- ud ) // um*
var resultlo = 0 ;
var resulthi = 0 ;
var temp = s[sp] ;
for ( var i=32 ; i ; --i ) {
resulthi <<= 1 ;
if (resultlo & 0x80000000) resulthi++ ;
resultlo <<= 1 ;
if (tos & 0x80000000) {
if ((resultlo + temp) > 0xffffffff) resulthi++ ;
resultlo += temp ;
}
tos <<= 1 ;
}
s[sp] = resultlo ;
tos = resulthi ;
}
var x_ummul = primitive("um*",forthummul)
describe("n1 n2 -- ud",any) ;
function forthmmul() { // m*
var temp = ((tos<0) ^ (s[sp]<0)) ;
tos = Math.abs(tos) ;
s[sp] = Math.abs(s[sp]) ;
forthummul() ;
if (temp) forthdnegate() ;
}
var x_mmul = primitive("m*",forthmmul)
describe("n1 n2 -- d",any) ;
function forthdless() { // d<
w = tos ;
tos = 0 ;
if (s[sp-1] < w) {
tos = -1 ;
} else {
if (s[sp-1] == w) {
if (s[sp-2] < s[sp]) tos = -1 ;
}
}
sp -= 3 ;
}
primitive("d<",forthdless) ;
describe("d1 d2 -- f",any) ;
function forthdequ() { // d=
tos = -((tos == s[sp-1]) & (s[sp] == s[sp-2]))
sp -= 3 ;
}
primitive("d=",forthdequ) ;
describe("d1 d2 -- f",any) ;
function forthumslashmod() { // ( d u1 -- u2 u3 )
// skip leading zeroes (not done)
// shift-and-subtract division
// tos = divisor
var quotient = 0 ;
var remainder = 0 ; // portion of divident
var divbit = 0 ;
if (tos) { // hi part not 0 ?
divbit = 0x80000000 ;
for ( ; divbit ; divbit>>>=1 ) { // skip trailinz zeroes
if ((tos & divbit) == 0) break; // "late in" in contrast to "early out"
}
}
for (var j=2 ; j ; j--) { // crunch 2x 32 bit
var divident = s[sp--] ; // next divident portion
for ( ; divbit ; divbit>>>=1) {
remainder <<= 1 ;
if (divident & divbit) remainder++ ;
quotient<<=1 ;
if (remainder>=tos) {
remainder-=tos ;
quotient++
}
}
divbit = 0x80000000 ;
}
tos = quotient ;
s[++sp] = remainder ;
}
primitive("um/mod",forthumslashmod) ;
describe("d u1 -- u2 u3",any) ;
function forthudslashmod() { // ( d1 u1 -- u2 d2 )
w = tos ;
s[++sp] = 0 ;
forthumslashmod() ;
s[++sp] = w ;
w = tos ;
tos = s[sp--] ;
forthumslashmod() ;
s[++sp] = tos ;
tos = w ;
}
var x_udslashmod = primitive("ud/mod",forthudslashmod) ;
describe("d1 u1 -- u2 d2",jsf) ;
// =================================================================================================
// bool
// =================================================================================================
definitions(forth) ;
function forthor() { tos |= s[sp--] ; } // or
var x_or = primitive("or",forthor) ;
describe("x1 x2 -- x3",any|foerthchen) ;
function forthand() { tos &= s[sp--] ; } // and
var x_and = primitive("and",forthand) ;
describe("x1 x2 -- x3",any|foerthchen) ;
function forthxor() { tos ^= s[sp--] ; } // xor
primitive("xor",forthxor) ;
describe("x1 x2 -- x3",any|foerthchen) ;
function forthinvert() { tos ^= -1 ; } // invert
primitive("invert",forthinvert) ;
describe("x1 -- x2",ans|jsf) ;
primitive("not",forthinvert) ; // not
describe("x1 -- x2",fig|f79) ;
// =================================================================================================
// logic
// =================================================================================================
function forthequ() { tos = -(tos == s[sp--]) ; } // =
var x_equ = primitive("=",forthequ) ;
describe("x1 x2 -- f",any) ;
function forthnequ() { tos = -(tos != s[sp--]) ; } // <>
var x_nequ = primitive("<>",forthnequ) ;
describe("x1 x2 -- f",any) ;
function forthmore() { tos = -(tos < s[sp--]) ; } // >
var x_more = primitive(">",forthmore) ;
describe("n1 n2 -- f",any) ;
function forthless() { tos = -(tos > s[sp--]) ; } // <
var x_less = primitive("<",forthless) ;
describe("n1 n2 -- f",any) ;
function forth0equ() { tos = -(tos == 0) ; } // 0=
var x_0equ = primitive("0=",forth0equ) ;
describe("x -- f",any) ;
function forth0nequ() { tos = -(tos != 0) ; } // 0<>
primitive("0<>",forth0nequ) ;
describe("x -- f",any) ;
function forth0less() { tos = -(tos < 0) ; } // 0<
var x_0less = primitive("0<",forth0less) ;
describe("n -- f",any) ;
function forth0greater() { tos = -(tos > 0) ; } // 0>
var x_0greater = primitive("0>",forth0greater) ;
describe("n -- f",any) ;
function forthuless() { // u<
w = s[sp--] ;
if (tos<0) tos += 0x100000000 ;
if (w<0) w += 0x100000000 ;
tos = -(w<tos) ;
}
primitive("u<",forthuless) ;
describe("u1 u2 -- f",any) ;
function forthumore() { // u>
w = s[sp--] ;
if (tos<0) tos += 0x100000000 ;
if (w<0) w += 0x100000000 ;
tos = -(w>tos) ;
}
primitive("u>",forthumore) ;
describe("u1 u2 -- f",any) ;
function forthwithin() { // ( x1 x2 x3 -- flag ) // within
w = s[sp--] ;
var temp = s[sp--] ;
var temp2 = tos ;
tos = -1 ;
if (w < temp2) {
if (w <= temp) {
if (temp < temp2) return ;
}
}
if (w > temp2) {
if (w <= temp) return ;
if (temp < temp2) return ;
}
tos++ ;
}
primitive("within",forthwithin) ;
describe("x1 x2 x3 -- f",any) ;
// =================================================================================================
// pictured number conversion
// =================================================================================================
// non standard stack: does currently not expect double, but single number
// that's why further implementation has been postponed - need double math first.
// ( d -- d )
var picturedoutpos ;
var picturedoutlen ;
function forthlesshash() { // <#
picturedoutpos = dp + paddistance ;
picturedoutlen = 0 ; // avoiding len calc allow to allot
} // during pic num conv
var x_lesshash = primitive("<#",forthlesshash) ;
describe("--",any) ;
function forthhold() {
m[--picturedoutpos] = tos ;
picturedoutlen++ ;
tos = s[sp--] ;
}
var x_hold = primitive("hold",forthhold) ;
describe("c --",any) ;
function forthsign() {
if (tos<0) {
m[--picturedoutpos] = 45 ;
picturedoutlen++ ;
}
tos = s[sp--]
}
var x_sign = primitive("sign",forthsign) ;
describe("n --",any) ;
function forthhashmore() { // #>
s[sp] = picturedoutpos ;
tos = picturedoutlen ;
} // during pic num conv
var x_hashmore = primitive("#>",forthhashmore) ;
describe("-- a n",any) ;
// =================================================================================================
// does>
// =================================================================================================
definitions(hidden) ;
// linkage code for word, created by defining word.
function dodoes() {
s[++sp] = tos ; tos = x[w] ; // push words address of defined word
r[++rp] = ip ; // nest
ip = m[tos++] ; // set ip to does> part, and tos to body of defined word
w = m[ip++] ; t[w]() ; // next
}
// compiled to end of create part by does>
// executed during execution of defining word
function setdoes() { // tos: xt of does> part
m[x[wc]] = ip+1 ; // created word points to does>
t[wc] = dodoes ; // created word linkage code is dodoes
}
var x_setdoes = primitive("setdoes",setdoes) ;
// =================================================================================================
// flow control
// =================================================================================================
definitions(hidden) ;
function forthbrfor() {
r[++rp]=tos ;
r[++rp]=tos ;
ip++ ;
tos=s[sp--] ;
}
var x_brfor=primitive("(for)",forthbrfor) ;
function forthbrnext() {
r[rp]-- ;
if (r[rp]) {
ip+=m[ip] ;
} else {
ip++ ;
rp-=2 ;
}
}
var x_brnext=primitive("(next)",forthbrnext) ;
function forthbrdo() {
r[++rp]=s[sp--] ;
r[++rp]=tos ;
ip++ ;
tos=s[sp--] ;
}
var x_brdo=primitive("(do)",forthbrdo) ;
function forthbrqdo() {
if ( tos == s[sp] ) {
sp-- ;
ip+=m[ip] ;
} else {
r[++rp]=s[sp--] ;
r[++rp]=tos ;
ip++ ;
}
tos=s[sp--] ;
}
var x_brqdo=primitive("(?do)",forthbrqdo) ;
// fig/f79 leave
function forthbrleave79() { r[rp] = r[rp-1]-1 ; }
var x_brleave79 = primitive("(leave)",forthbrleave79) ;
// ans/f83 leave
function forthbrleave() {
rp -= 2 ;
ip = m[ip] ;
ip += m[ip] ;
}
var x_brleave=primitive("(leave)",forthbrleave) ;
function forthbrqleave() {
if (tos) {
rp -= 2 ;
ip = m[ip] ;
ip += m[ip] ;
} else {
ip++ ;
}
tos=s[sp--] ;
}
var x_brqleave=primitive("(?leave)",forthbrqleave) ;
function forthbrloop() {
r[rp]++ ;
if ( r[rp] != r[rp-1] ) {
ip+=m[ip] ;
} else {
ip++ ;
rp-=2 ;
}
}
var x_brloop=primitive("(loop)",forthbrloop) ;
describe("--",jsf) ;
function forthbrplusloop() { // (+loop)
w = r[rp] - r[rp-1] ;
r[rp] += tos ;
tos=s[sp--] ;
if ( (( r[rp] - r[rp-1]) ^ w ) > 0 ) {
ip+=m[ip] ;
} else {
ip++ ;
rp-=2 ;
}
}
var x_brplusloop=primitive("(+loop)",forthbrplusloop) ;
describe("n --",jsf) ;
function forthbrunloop() { rp-=2 ; }
var x_brunloop = primitive("(unloop)",forthbrunloop) ;
describe("--",jsf) ;
function forthbrof() { // (of)
w = tos ;
tos = s[sp--] ;
if (w == tos) {
tos = s[sp--]
ip++
} else {
ip+=m[ip] ;
}
}
var x_brof = primitive("(of)",forthbrof) ;
describe("x1 x2 -- x1 |",jsf) ;
definitions(forth) ;
function forthexecute() { w=tos ; tos=s[sp--] ; t[w]() ; }
var x_execute = primitive("execute",forthexecute) ;
describe("xt --",any) ;
function forthperform() { w=m[tos] ; tos=s[sp--] ; t[w]() ; }
var x_perform = primitive("perform",forthperform) ;
describe("a --",jsf) ;
function forthi() { s[++sp]=tos ; tos=r[rp] ; }
var x_i=primitive("i",forthi) ;
describe("-- x",any) ;
function forthj() { s[++sp]=tos ; tos=r[rp-2] ; }
var x_j=primitive("j",forthj) ;
describe("-- x",any) ;
definitions(hidden) ;
var controlflow = new Array("","if", "", "begin", "while", "do or ?do", "for", "case", "of")
var controlflowwant = new Array("","else or then","then","while,until or again","repeat","loop or +loop", "next", "endcase", "endof")
function forthunstructured() {
systemerror[66] = "unstructured, missing " + controlflow[tos] + ", expected " + controlflowwant[s[sp]] ;
throwerror(-66) ;
}
var x_unstructured = primitive("unstructured",forthunstructured)
// =================================================================================================
// strings
// =================================================================================================
definitions(forth) ;
function forthmove() { // move
if ( s[sp] > s[sp+1] ) {
dest = s[sp--] + tos ;
src = s[sp--] + tos ;
for ( ; tos ; tos-- ) m[--dest] = m[--src] ;
} else {
var dest = s[sp--] ;
var src = s[sp--] ;
for ( ; tos ; tos-- ) m[dest++] = m[src++] ;
}
tos = s[sp--] ;
}
var x_move = primitive("move",forthmove) ;
describe("a1 a2 u --",any) ;
primitive("cmove",forthmove) ;
describe("a1 a2 u",any) ;
definitions(hidden) ;
function forthmovestr() { // ( a1 n a2 -- ) // move$
w = s[sp] ;
m[tos++] = w ;
s[sp] = tos ;
tos = w ;
forthmove() ;
}
var x_movestr = primitive("move$",forthmovestr) ;
describe("a1 n a2 --",jsf) ;
definitions(forth) ;
function forthmintrailing() { // a1 n1 -- a2 n2 )
var temp = s[sp] + tos ;
for ( i=tos ; i ; i-- ) {
if (m[--temp] != 32) break ;
tos-- ;
}
}
var x_mintrailing = primitive("-trailing",forthmintrailing) ;
describe("a1 u1 -- a2 u2",any) ;
// ----- number input conversion -----
function forthdigit() { // ( c -- u | -1 )
tos -= 48 ;
if ( tos > 9 ) {
if ( tos < 17) tos = -1 ;
tos -= 7 ;
}
if ( tos > 41 ) tos -= 32 ;
if ( tos >= 0) {
if (tos < m[base]) return ;
}
tos = -1 ;
}
var x_digit = primitive("digit",forthdigit);
describe("c -- u|-1",jsf) ;
definitions(hidden) ;
function forthqsinglenumber() { // a n -- x -1 | 0 )
var digit ;
var sign=0 ;
var radix=m[base] ;
i = tos ; // number of digits to test/convert
tos = -1 ; // assume valid number
w = s[sp] ; // addr of next digit
s[sp] = 0 ; // accumulator
if ( m[w] == 45 ) { // leading -
sign = -1 ;
w++ ; // strip
i-- ;
}
for ( var i ; i ; i-- ) { // for all digits
digit = m[w++] - 48 ; // read digit
if ( digit == -2 ) exception("no input support for floating point numbers yet") ;
if ( digit > 9 ) {
if ( digit < 17) { tos = 0 ; break ; }
digit -= 7 ;
}
if ( digit > 41 ) digit -= 32 ;
if ( digit < 0 ) { tos = 0 ; break ; }
if (digit >= radix) { tos = 0 ; break ; }
s[sp] *= radix ;
s[sp] += digit ;
}
if (tos) {
if (sign) s[sp] = -s[sp] ;
s[sp] &= 0xffffffff ;
} else {
sp-- ; // drop string address
}
}
// parseFloat(string) ;
function forthqnumber() { // a n -- x -1 | 0 )
if (m[s[sp]+tos-1]==46) {
exception("no input support for double length numbers yet") ;
sp-- ; tos=0 ;
} else {
forthqsinglenumber()
}
}
var x_qnumber = primitive("?number",forthqnumber) ;
function forthinterpretnumber() { // ( a n -- x -1 | d -1 | r -1 | -1 | 0 )
forthqnumber() ;
if (tos) {
if (m[state]) {
m[dp++] = x_lit ;
m[dp++] = s[sp--] ;
tos = -1 ;
}
}
}
var x_interpretnumber = primitive("interpretnumber",forthinterpretnumber) ;
// function forthinterpretnumber()
// first char = - ?
// if remember skip then
// for all chars in string:
// next char = digit ?
// if accumulate
// else
// char = . ?
// if
//
// else
// otherlegalchars? none if NaN then
// then
// then
// next
// negate?
// state @ if
// compile lit
// then ;
// =================================================================================================
// dictionary, compiling
// =================================================================================================
definitions(forth) ;
// this has been speeded up a lot, by using an
// improvement suggested by TheBlueWizard.
function forthwords() { // words
for (var i=wc; i; i--) {
if (h[i]) {
if (m[context] & ds[i]) {
if (m[compliance] & ds[i]) querytype(h[i]+" ") ;
}
}
}
}
var x_words = primitive("words",forthwords) ;
describe("--",f83|ans|jsf|foerthchen|only) ;
function forthvlist() { forthwords() ; }
primitive("vlist",forthvlist) ;
describe("--",f79|fig) ;
function forthhere() { s[++sp]=tos ; tos=dp ; } // here
var x_here= primitive("here",forthhere) ;
describe("-- a",any) ;
function forthallot() { // allot
if ((dp+tos)>dictionaryfull) {
throwerror(-8) ;
} else {
dp+=tos ;
tos=s[sp--] ;
}
}
var x_allot= primitive("allot",forthallot) ;
describe("n --",any) ;
function forthhide() { hf[wc] &= (!smudgebit) ; } // hide
var x_hide= primitive("hide",forthhide) ;
describe("--",f83) ;
function forthreveal() { hf[wc] |= smudgebit ; } // reveal
var x_reveal= primitive("reveal",forthreveal) ;
describe("--",f83) ;
function comma(x) {
if ((dp+1) >= dictionaryfull) {
throwerror(-8) ;
} else {
m[dp++] = x ;
}
}
function forthcomma() { comma(tos) ; tos = s[sp--] ; } // ,
var x_comma = primitive(",",forthcomma) ;
describe("x --",any) ;
var x_ccomma = primitive("c,",forthcomma) ; // c,
describe("c --",any) ;
function compile() { for (var i=0 ; i<arguments.length ; jscomma(arguments[i++])) ; }
definitions(hidden) ;
// non-standard function, internal use. find (more standard) builds on this one.
// return header number = xt
function forthsearch1() { // ( packedname -- a2 | 0 )
for (var i=wc; i; i--) { // loop through headers last first
w = h[i] ;
if (w) { // header exists
if (m[context] & ds[i]) { // header in context dir
if (hf[i] & smudgebit) { // smudge bit set too ?
if (!m[casesensitive]) w = w.toLowerCase() ;
if (w == tos) { // header match ?
if (m[compliance] & ds[i]) { // complies with standard ?
tos = i; // yes, return xt
return;
}
}
}
}
}
}
tos = 0; // all tried, no match
}
// this can be done better, but works for now.
function forthsearch() { // ( a1 n -- a2 | 0 )
forthpack();
if (!m[casesensitive]) tos = tos.toLowerCase() ;
var packedname = tos ;
var orgcontext = m[context] ;
forthsearch1() ; // search context voc first
if (!tos) { // go on, search voc stack if not found
for ( var i=vocstack.length ; i ; ) {
tos = 0 ; // assume "not found"
i-- ;
if (m[context] != vocstack[i]) { // don't search voc, if already searched
m[context] = vocstack[i] ; // make next voc context
tos = packedname ;
forthsearch1() ;
}
if (tos) break ; // found ? escape
}
}
m[context] = orgcontext ; // restore original context
}
var x_search= primitive("search",forthsearch) ;
definitions(forth) ;
function forthfind() { // ( a -- a 0 | x1 1 | xt -1 ) (1=immediate)
s[++sp] = tos ;
s[++sp] = tos+1 ;
tos = m[tos] & 255 ;
forthsearch() ; // ( a 0 | a xt )
if (tos) {
s[sp] = tos;
if (hf[tos] & precedencebit) {
tos = 1 ;
} else {
tos = -1 ;
}
}
}
var x_find= primitive("find",forthfind) ;
describe("a1 -- a2 0 | a2 xt",ans|f83|jsf) ;
function forthtobody() { // ( a1 -- a2 )
if (tos <= primitives) throwerror(-31) ;
tos = x[tos] + 1 ;
}
var x_tobody = primitive(">body",forthtobody) ;
describe("a1 -- a2",any) ;
function forthbodyfrom() { // ( a1 -- a2 )
tos-- ;
for (var i=wc; i; i--) { // loop through headers last first
if (h[i]) {
if (x[i] == tos) { // word pointer match ?
tos = i; // yes, return xt
return;
}
}
}
throwerror(-65) ;
}
primitive("body>",forthbodyfrom) ;
describe("a1 -- a2",jsf) ;
definitions(hidden) ;
function forthqimm() { tos = -(hf[tos] & precedencebit) ; } // ( xt -- f )
var x_qimm = primitive("?immediate",forthqimm) ; // ?immediate
function forthcompiling() { s[++sp] = tos ; tos = m[state] ; } // compiling
var x_compiling = primitive("compiling",forthcompiling) ;
definitions(forth) ;
function forthimmediate() { hf[wc] |= precedencebit ; } // immediate
primitive("immediate",forthimmediate) ;
describe("--",any) ;
function forthbrclose() { m[state] = true ; } // ]
var x_brclose = primitive("]",forthbrclose) ;
describe("--",any) ;
function forthbropen() { m[state] = false ; } // [
var x_bropen = primitive("[",forthbropen,immediate) ;
describe("--",any) ;
definitions(hidden) ;
function forthnewheader() { // newheader
forthpack() ;
newheader(tos) ;
tos=s[sp--] ;
}
var x_newheader = primitive("newheader",forthnewheader) ;
definitions(forth) ;
function forthdotname() { // ( xt -- ) // .name
type(h[tos]) ;
tos = s[sp--] ;
}
var x_dotname = primitive(".name",forthdotname) ;
describe("xt --",jsf) ;
function forthname() { // ( xt -- a n ) // name
sp++ ;
s[++sp] = h[tos] ;
tos = dp ;
s[sp-1] = tos ;
unpack() ;
}
primitive("name",forthname) ;
describe("x1 -- a u",jsf) ;
definitions(hidden) ;
function forthcreateheader() {
s[++sp] = tos ;
tos = bl ;
forthparse() ;
forthnewheader() ;
}
var x_createheader = primitive("createheader",forthcreateheader) ;
function forthuse() {
forthcreateheader() ;
forthcomma() ;
t[wc] = nexthilevel ;
}
var x_use = primitive("use",forthuse) ;
definitions(forth) ;
function forthcolonnoname() { // :noname
s[++sp] = tos ;
newheader("") ;
tos = wc ;
comma(x_nest) ;
m[state] = -1 ;
t[wc] = nexthilevel ;
}
primitive(":noname",forthcolonnoname)
describe("-- a",ans|jsf) ;
function forthunused() {
s[++sp] = tos ;
tos = dictionaryfull - dp ;
}
primitive("unused",forthunused) ;
describe("-- u",ans|jsf) ;
function forthheap() { // ( -- a )
s[++sp] = tos ;
tos = heapend ;
}
primitive("heap",forthheap) ;
describe("-- a",jsf) ;
function forthbrmarker() { // ( wc dp -- )
dp = tos ;
wc = s[sp--] ;
m[lastxt] = wc ;
tos = s[sp--] ;
}
primitive("(marker)",forthbrmarker) ;
describe("wc dp heap --",jsf) ;
// =================================================================================================
// mass storage
// =================================================================================================
// ------------------------------------------- memory drive --------------------------------------------
var ramblock = new Array() ;
var screenline ;
function saveblock() {
for (i=screenline.length ; i<16 ; i++) screenline.push("") ;
for (i=screenline.length ; i>16 ; i--) screenline.pop() ;
ramblock.push(screenline) ;
}
screenline = new Array() ;
screenline.push("( ramdrive block 0 - essential block words -load- )") ;
screenline.push(": copy (s u1 u2 -- ) swap block swap buffer c/s move update ;") ;
screenline.push(": clear (s u -- ) buffer c/s blank update ;") ;
screenline.push(": index1 (s u -- ) dup scr ! 2 .r space 0 .line ;") ;
screenline.push(": index (s u1 u2 -- ) 1+ swap ?do cr i index1 loop ;") ;
screenline.push(": ls (s -- ) 0 capacity 1- index ;") ;
screenline.push(": w (s -- ) last @ 1+ 1 do i name dup if ") ;
screenline.push(" 2dup info s\" \" ...info i stackeffect ...info") ;
screenline.push(" then 2drop loop ;") ;
screenline.push(": --> (s -- ) blk @ 1+ block c/s !source >in off ; immediate") ;
screenline.push(": uppercase dup char a char z 1+ within 32 and - ;") ;
screenline.push(": p (s -- ) scr @ 1- 0 max scr ! ;") ;
screenline.push(": n (s -- ) scr @ 1+ capacity 1- min scr ! ;") ;
screenline.push(": view (s -- ) begin key dup esc <> while uppercase") ;
screenline.push(" dup char N = if n else dup char P = if p then then") ;
screenline.push(" drop cls l repeat drop ;") ;
saveblock() ;
screenline = new Array() ;
screenline.push("( ramdrive block 1 - MARKER + info screen words -load- )") ;
screenline.push(": marker here last @ create , ,") ;
screenline.push(" does> skim swap @ (marker) ;") ;
screenline.push("") ;
screenline.push(": cr2 (s -- ) s\" \" info ;") ;
screenline.push("") ;
screenline.push(": .line2 (s u -- ) c/l * screen + c/l -trailing info ;") ;
screenline.push("") ;
screenline.push("( list screen on info window )") ;
screenline.push(": list2 (s u -- ) scr ! l/s 0 do i .line2 loop ;") ;
screenline.push("") ;
screenline.push("( list all screens on info, enable backscroll )") ;
screenline.push(": sources (s -- ) capacity 0 do i list2 loop all ;") ;
saveblock() ;
screenline = new Array() ;
screenline.push("( ramdrive block 2 - hex dump -load- )") ;
screenline.push("hidden definitions 6 constant dumps/line");
screenline.push(": safe-emit (s c -- ) dup bl 128 within 0=") ;
screenline.push(" if drop char . then emit ;") ;
screenline.push(": ######## (s u -- ) 0 <# 8 for # next #> type ;") ;
screenline.push(": .cell (s u -- ) 16 base exchange swap ######## space base ! ;") ;
screenline.push(": .addr (s u -- ) .cell ;") ;
screenline.push(": pad_dump1 (s n -- ) 4 swap - 3 * spaces ;") ;
screenline.push(": dump_cells (s a n -- ) for skim .cell next drop ;") ;
screenline.push(": dump_chars (s a n -- ) for count safe-emit next drop ;") ;
screenline.push(": dump1line (s a n -- ) dumps/line min dup if over .addr") ;
screenline.push(" 2 spaces 2dup dump_cells dup pad_dump1 2 spaces") ;
screenline.push(" 2dup dump_chars then 2drop ;") ;
screenline.push("forth definitions hidden") ;
screenline.push(": dump (s a n -- ) begin ?dup while 2dup cr dump1line") ;
screenline.push(" dumps/line /string repeat drop ; forth") ;
saveblock() ;
screenline = new Array();
screenline.push("( ramdrive block 3 - modified retro editor )") ;
screenline.push(": line (s u -- a ) c/l * screen + ;") ;
screenline.push(": s (s u -- ) scr ! ;") ;
screenline.push(": ia (s a u -- ) line + >r 0 parse r> swap cmove ;") ;
screenline.push(": r (s u -- ) 0 swap ia ;") ;
screenline.push(": d (s u -- ) line c/l blank ;") ;
screenline.push(": x (s -- ) clear ;") ;
screenline.push(": v (s -- ) l ;") ;
screenline.push("( extensions: bubble up and down lines )") ;
screenline.push(": >pad (s a n -- ) pad swap move ;") ;
screenline.push(": pad> (s a n -- ) pad -rot move ;") ;
screenline.push(": lines (s u1 u2 -- a1 a2 ) line swap line swap ;") ;
screenline.push(": xchg lines over >r dup c/l >pad c/l move r> c/l pad> ;") ;
screenline.push(": bu (s u1 -- ) ?dup if dup 1- xchg then ;") ;
screenline.push(": bd (s u1 -- ) dup l/s 1- < if dup 1+ bu then drop ;") ;
saveblock() ;
screenline = new Array("( ramdrive block 4 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 5 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 6 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 7 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 8 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 9 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 10 - empty )") ; saveblock() ;
screenline = new Array("( ramdrive block 11 - empty )") ; saveblock() ;
// ---------------------------- ram drive ----------------------------
function loadblockfromram(n,a) { // unpack block n to address
debug("ram drive: block " + n + " to addr " + a) ;
var temp = a ;
for ( i=0; i<16; i++ ) {
s[++sp] = lineofspaces.substr(0,64) ; tos = temp ; unpack() ;
s[++sp] = ramblock[n][i].substr(0,64) ; tos = temp ; unpack() ;
temp += 64 ;
}
return a ;
}
function savebuftoram(addr,blocknum) {
debug("ram drive: from " + addr + " to ramblock " + blocknum)
for ( i=0; i<16; i++ ) {
ramblock[blocknum][i] = pack(addr,64) ;
addr += 64 ;
}
}
function ramdrivecapacity() { return ramblock.length } ;
// ------------------------- cookie drive ------------------------------
var cookiesectorsize = 1024 // decrease size to spread block across multiple cookies
function loadblockfromcookie(blknum,destaddr) { // unpack block to address
debug("cookie drive: block " + blknum + " to addr " + destaddr) ;
for (var i=0 ; i<1024 ; i+=cookiesectorsize) {
var cookiename = (cookiebasename + blknum + "_" + i) ;
var temp = (readcookie(cookiename, destaddr+i))
if (temp) {
unpackstring(temp.substr(0,cookiesectorsize),destaddr+i) ;
} else {
temp = destaddr+i ;
for (var j=0 ; j<cookiesectorsize ; j++) m[temp++] = bl ;
}
}
return destaddr ;
}
function savebuftocookie(addr,blknum) {
debug("cookie drive: from " + addr + " to block " + blknum)
for (var i=0 ; i<1024 ; i+=cookiesectorsize) setcookie((cookiebasename + blknum + "_" + i), pack(addr+i,cookiesectorsize), null, cookieexpirationdate) ;
}
function cookiedrivecapacity() { return maxcookies ; } // for now
function localcapacity() { return (ramdrivecapacity() + cookiedrivecapacity()) } ;
// ------------------------------ peer drives ------------------------------
// -------------------------------------------------------------------------
function capacity() { return localcapacity() ; }
function forthcapacity() { s[++sp] = tos ; tos = capacity() ; }
primitive("capacity",forthcapacity) ;
describe("-- u",jsf) ;
function forthlocalcapacity() { s[++sp] = tos ; tos = localcapacity() } ;
primitive("localcapacity",forthlocalcapacity) ;
describe("-- u",jsf) ;
// ------------------------ buffers ------------------------
// block mapping hardcoded in here
function savebuf(buffer) {
var starttime = new Date().getTime();
var bufaddr = buf[buffer] ;
var blknum = bufblk[buffer] ;
if (blknum<maxcookies) {
savebuftocookie(bufaddr,blknum) ;
} else {
var temp = localcapacity() ;
savebuftoram(bufaddr,blknum-maxcookies) ;
}
bufdirty[buffer] = 0 ; // set clean
var stoptime = new Date().getTime();
debug("block " + blknum + " write took " + (stoptime-starttime) + "ms") ;
}
function loadblock(blknum,buffer) {
var starttime = new Date().getTime();
if (blknum<maxcookies) {
var blockdata = loadblockfromcookie(blknum,buffer) ;
} else {
var temp = localcapacity() ;
blockdata = loadblockfromram(blknum-maxcookies,buffer) ;
}
var stoptime = new Date().getTime();
debug("block " + blknum + " read took " + (stoptime-starttime) + "ms") ;
return blockdata ;
}
// --------------------------------------------------------------
var hotbuffer ; // for update
function forthblockorbuffer(flag) { // ( u -- a ) / flag=true:block false:buffer
if ((tos>=capacity()) || (tos<0)) throwerror(-35) ;
if (blockstat[tos] >= 0) { // block already mapped:
hotbuffer = blockstat[tos] ;
tos = buf[hotbuffer] ; // return buffer address
} else { // block not mapped:
nextbuf++ ; // next available buffer
nextbuf %= maxbufs ;
if (bufblk[nextbuf] >= 0) { // buffer used for another block
if (bufdirty[nextbuf]) savebuf(nextbuf) ; // dirty ?
blockstat[bufblk[nextbuf]] = -1; // write block info "unbuffered"
}
var temp = tos ;
if (flag) {
tos = loadblock(tos,buf[nextbuf]) ; // block: fill block with data from mass memory.
} else {
tos = buf[nextbuf] ; // buffer: indefinite buffer contents.
}
hotbuffer = nextbuf ;
bufblk[nextbuf] = temp ; // associate buf with block#
blockstat[temp] = nextbuf ; // set block info "buffered in ..."
}
}
function forthbuffer() { forthblockorbuffer(false) ; } // ( u -- a )
var x_buffer = primitive("buffer",forthbuffer) ;
describe("u -- a",any) ;
function forthblock() { forthblockorbuffer(true) ; } // ( u -- a )
var x_block = primitive("block",forthblock) ;
describe("u -- a",any) ;
function forthupdate() { bufdirty[hotbuffer] = -1 ; }
primitive("update",forthupdate) ;
describe("--",any) ;
function forthsavebuffers() {
for (var i=0 ; i<maxbufs ; i++ ) { // for all buffers
if (bufdirty[i]) savebuf(i) ; // save if dirty
blockstat[bufblk[i]] = -1; // write block info "unbuffered"
}
}
primitive("save-buffers",forthsavebuffers) ;
describe("--",any) ;
function forthemptybuffers() {
for (var i=0 ; i<maxbufs ; i++ ) {
if (bufblk[i]>=0) { // buffer has block in ?
blockstat[bufblk[i]] = -1 ; // mark block as not buffered anymore
bufblk[i] = -1 ; // mark buffer as not containing a block
bufdirty[i] = 0 ; // set clean
}
}
}
primitive("empty-buffers",forthemptybuffers) ;
describe("--",any) ;
function forthblockstats() {
cr() ; type("checking blocks:") ;
var temp = capacity()
for (var i=0 ; i<temp ; i++) {
if (blockstat[i] != -1) {
cr() ;
type(" blk #" + i + ": buf " + blockstat[i]);
}
}
}
function forthbufstats() {
cr() ; type("checking buffers:")
for ( i=0 ; i<maxbufs ; i++ ) {
cr() ;
type(" buf #" + i + ":") ;
if (bufblk[i] < 0) {
type(" empty") ;
} else {
type( " blk " + bufblk[i]) ;
}
if (bufdirty[i]) type(" dirty") ;
}
forthblockstats() ;
}
primitive("bufstats",forthbufstats) ;
describe("--",jsf) ;
// =================================================================================================
// vocabularies
// =================================================================================================
// i'll try to use the standards selector to implement conventional vocabularies
definitions(forth) ;
function dovocabulary() {
w = x[w] ;
m[context] = m[w] ;
standard = ((standard & (higheststandard<<1)-1)) | m[context] ;
}
function forthvocabulary() {
if (nextvocabulary>=0x20000000) {
throwerror(-69) ;
} else {
forthcreateheader() ;
vocname.push(wc) ;
t[wc] = dovocabulary ;
nextvocabulary <<= 1 ;
m[dp++] = nextvocabulary ;
forthreveal() ;
}
}
primitive("vocabulary",forthvocabulary) ;
describe("<new vocabulary name> --",any) ;
function forthonly() {
for ( var i=vocstack.length ; i ; i--) vocstack.pop() ;
m[context] = only ;
vocstack.push(only) ; }
primitive("only",forthonly) ;
describe("--",any) ;
vocname.push(wc) ;
function forthforth() { m[context] = forth ; }
primitive("forth",forthforth) ;
describe("--",any|only) ;
vocname.push(wc) ;
function forthhidden() { m[context] = hidden ; }
primitive("hidden",forthhidden) ;
describe("--",jsf|f83|ans) ;
vocname.push(wc) ;
function forthteststuff() { m[context] = teststuff ; }
primitive("teststuff",forthteststuff) ;
describe("--",jsf) ;
vocname.push(wc) ;
function forthdefinitions() { m[current] = m[context] ; }
primitive("definitions",forthdefinitions) ;
describe("--",any) ;
function forthorder() {
printvocname(m[context]) ;
for (var i=vocstack.length ; i ; i--) printvocname(vocstack[i-1]) ;
type(" ") ; printvocname(m[current]) ;
}
primitive("order",forthorder) ;
describe("--",ans|jsf|only) ;
function forthalso() { vocstack.push(m[context]) ; }
primitive("also",forthalso) ;
describe("--",ans|jsf) ;
function forthprevious() { m[context] = vocstack.pop() ; }
primitive("previous",forthprevious) ;
describe("--",ans|jsf) ;
function forthvocs() { for (i=vocname.length ; i ; type(h[vocname[--i]] + " ")) ; }
primitive("vocs",forthvocs) ;
describe("--",fig|f79|f83|jsf) ;
// =================================================================================================
// floating point
// =================================================================================================
definitions(teststuff) ;
// fconstants, testing
function forth1point5() { f.push(ftos) ; ftos=1.5 ; } ; primitive("1.5",forth1point5) ;
function forthmin1point5() { f.push(ftos) ; ftos=-1.5 ; } ; primitive("-1.5",forthmin1point5) ;
function forth2point8() { f.push(ftos) ; ftos=2.8 ; } ; primitive("2.8",forth2point8) ;
function forthmin2point8() { f.push(ftos) ; ftos=-2.8 ; } ; primitive("-2.8",forthmin2point8) ;
definitions(forth) ;
function forthfdots() { // f.s
f.push(ftos) ;
for (var i=1 ; i < f.length ; type(f[i++] + " ")) ;
ftos = f.pop() ;
}
primitive("f.s",forthfdots) ;
describe("--",any) ;
function forthfdrop() { ftos = f.pop() ; } // fdrop
primitive("fdrop",forthfdrop) ;
describe("r --",any) ;
function forthfdup() { f.push(ftos) ; } // fdup
primitive("fdup",forthfdup) ;
describe("r -- r r",any) ;
function forthfswap() { // fswap
w = f.pop() ;
f.push(ftos) ;
ftos = w ;
}
primitive("fswap",forthfswap) ;
describe("r1 r2 -- r2 r1",any) ;
function forthfover() { // fover
f.push(ftos) ;
ftos = f[f.length-2] ;
}
primitive("fover",forthfover) ;
describe("r1 r2 -- r1 r2 r1",any) ;
function forthffetch() { // f@
f.push(ftos) ;
ftos = (m[tos]) ;
tos = s[sp--] ;
}
primitive("f@",forthffetch) ;
describe("a -- r",any) ;
function forthfstore() { // f!
m[tos] = ftos ;
ftos = f.pop() ;
tos = s[sp--] ;
}
primitive("f!",forthfstore) ;
describe("r a --",any) ;
function forthfequ() { // f=
s[++sp] = tos ;
tos = -(ftos == f.pop()) ;
}
primitive("f=",forthfequ) ;
describe("r1 r2 -- f",any) ;
function forthfnequ() { // f<>
s[++sp] = tos ;
tos = -(ftos != f.pop()) ;
}
primitive("f<>",forthfnequ) ;
describe("r1 r2 -- f",any) ;
function forthfmore() { // f>
s[++sp] = tos ;
tos = -(f.pop() > ftos) ;
}
primitive("f>",forthfmore) ;
describe("r1 r2 -- f",any) ;
function forthfless() { // f<
s[++sp] = tos ;
tos = -(f.pop() < ftos) ;
}
primitive("f<",forthfless) ;
describe("r1 r2 -- f",any) ;
function forthf0equ() { // f0=
s[++sp] = tos ;
tos = -(ftos == 0) ;
ftos = f.pop() ;
}
primitive("f0=",forthf0equ) ;
describe("r -- f",any) ;
function forthf0nequ() { // f0<>
s[++sp] = tos ;
tos = -(ftos != 0) ;
ftos = f.pop() ;
}
primitive("f0<>",forthf0nequ) ;
describe("r -- f",any) ;
function forthf0less() { // f0<
s[++sp] = tos ;
tos = -(ftos < 0) ;
ftos = f.pop() ;
}
primitive("f0<",forthf0less) ;
describe("r -- f",any) ;
function forthf0greater() { // f0>
s[++sp] = tos ;
tos = -(ftos > 0) ;
ftos = f.pop() ;
}
primitive("f0>",forthf0greater) ;
describe("r -- f",any) ;
function forthfnegate() { // fnegate
ftos = -ftos ;
}
primitive("fnegate",forthfnegate) ;
describe("r1 -- r2",any) ;
function forthfabs() { // fabs
ftos = Math.abs(ftos) ;
}
primitive("fabs",forthfabs) ;
describe("r1 -- r2",any)
function forthfround() { // fround
ftos = Math.round(ftos) ;
}
primitive("fround",forthfround) ;
describe("r1 -- r2",any)
function forthfdepth() { // fdepth
s[sp++] = tos ;
tos = f.length ;
}
primitive("fdepth",forthfdepth) ;
describe(" -- u",any)
function forthdtof() { // d>f
f.push(ftos) ;
ftos = tos * 0x100000000 + s[sp--] ;
tos = s[sp--] ;
}
primitive("d>f",forthdtof) ;
describe("d --",jsf|ans) ;
function forthftod() { // f>d
s[++sp] = tos ;
tos = ftos ;
ftos = f.pop() ;
s[++sp] = tos & 0xffffffff ;
tos = tos/0x100000000
if (tos<0) tos+=floorfix ;
tos = Math.floor(tos) ;
}
primitive("f>d",forthftod) ;
describe("r -- d",jsf|ans) ;
function forthstof() { // s>f
f.push(ftos) ;
ftos = tos ;
tos = s[sp--] ;
}
primitive("s>f",forthstof) ;
describe("x --",jsf) ;
function forthfplus() { // f+
ftos += f.pop() ;
}
primitive("f+",forthfplus) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfminus() { // f-
ftos = f.pop()-ftos ;
}
primitive("f-",forthfminus) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfmul() { // f*
ftos *= f.pop() ;
}
primitive("f*",forthfmul) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfdiv() { // f/
var temp = f.pop() ;
ftos = temp/ftos ;
}
primitive("f/",forthfdiv) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfsin() { // fsin
ftos = Math.sin(ftos) ;
}
primitive("fsin",forthfsin) ;
describe("r1 -- r2",jsf|ans) ;
function forthfcos() { // fcos
ftos = Math.cos(ftos) ;
}
primitive("fcos",forthfcos) ;
describe("r1 -- r2",jsf|ans) ;
function forthftan() { // ftan
ftos = Math.tan(ftos) ;
}
primitive("ftan",forthftan) ;
describe("r1 -- r2",jsf|ans) ;
function forthfasin() { // fasin
ftos = Math.asin(ftos) ;
}
primitive("fasin",forthfasin) ;
describe("r1 -- r2",jsf|ans) ;
function forthfatan() { // fatan
ftos = Math.atan(ftos) ;
}
primitive("fatan",forthfatan) ;
describe("r1 -- r2",jsf|ans) ;
function forthfatan2() { // fatan2
ftos = Math.atan2(f.pop(),ftos) ;
}
primitive("fatan2",forthfatan2) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfacos() { // facos
ftos = Math.acos(ftos) ;
}
primitive("facos",forthfacos) ;
describe("r1 -- r2",jsf|ans) ;
function forthfpower() { // f**
ftos = Math.pow(f.pop(),ftos) ;
}
primitive("f**",forthfpower) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfln() { // fln
ftos = Math.log(ftos) ;
}
primitive("fln",forthfln) ;
describe("r1 -- r2",jsf|ans) ;
// function forthflog() { // flog
// ftos = Math.log(10,ftos) ;
// }
// primitive("flog",forthflog) ;
// describe("r1 -- r2",jsf|ans) ;
// (Math.log) : e based
function forthfalog() { // falog
ftos = Math.pow(10,ftos) ;
}
primitive("falog",forthfalog) ;
describe("r1 -- r2",jsf|ans) ;
function forthfsqrt() { // fsqrt
ftos = Math.sqrt(ftos) ;
}
primitive("fsqrt",forthfsqrt) ;
describe("r1 -- r2",jsf|ans) ;
function forthfmin() { // fmin
ftos = Math.min(ftos,f.pop()) ;
}
primitive("fmin",forthfmin) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfmax() { // fmax
ftos = Math.max(ftos,f.pop()) ;
}
primitive("fmax",forthfmax) ;
describe("r1 r2 -- r3",jsf|ans) ;
function forthfdot() { // f.
type(ftos + " ") ;
ftos = f.pop() ;
}
primitive("f.",forthfdot) ;
describe("r --",jsf|ans) ;
function forthpi() { // pi
f.push(ftos) ;
ftos = Math.PI ;
}
primitive("pi",forthpi) ;
describe("-- r",jsf|ans) ;
function forthreciproc() { // 1/F
ftos = 1/ftos ;
}
primitive("1/f",forthreciproc) ;
describe("r1 -- r2",jsf|ans) ;
function forthfcomma() { m[dp++] = ftos ; ftos = f.pop() ; } // f,
var x_fcomma = primitive("f,",forthfcomma) ;
describe("r --",any) ;
primitive("falign",noop,immediate) // falign
describe("--",ans) ;
primitive("faligned",noop,immediate) // faligned
describe("--",ans) ;
// =================================================================================================
// heap
// =================================================================================================
var nusedchunks = 0 ;
var nfreechunks = 0 ;
// return data address of chunk
function newchunk(size) {
m[heapend++] = nusedchunks ;
m[heapend++] = size ;
usedchunk[nusedchunks++] = heapend ;
var temp = heapend ;
heapend += tos ;
return temp ;
}
// return data address of chunk
function splitchunk(fit,newsize) {
var chunkaddr = freechunk[fit] ;
var chunksizeleft = m[chunkaddr-1] - (newsize+2) ;
if ((chunksizeleft) > 0) { // split chunk into two:
m[chunkaddr-1] = chunksizeleft++ ; // new size old chunk
chunkaddr += chunksizeleft ; // new addr new chunk
m[chunkaddr++] = newsize ; // new size new chunk
} else { // use chunk completely:
freechunk[fit] = freechunk[--nfreechunks] ; // last chunk takes place of used chunk
freechunk.pop() ; // shorten array of freed chunks
}
m[chunkaddr-2] = nusedchunks ; // index into usedchunks array to this chunk
usedchunk[nusedchunks++] = chunkaddr ; // move new chunk to usedchunks
return chunkaddr ;
}
function searchfit(size) {
var fit = -1 ;
if (nfreechunks) {
var temp = 0xffffffff ; // any chunk is better
for (var i=0 ; i<nfreechunks ; i++) {
var slack = m[freechunk[i]-1] - size ;
if (slack == 0) return i
if (slack > 2 ) {
if (!fittype) return i ;
if ( slack < temp ) {
fit = i ;
temp = slack ;
}
}
}
}
return fit ;
}
function forthallocate() { // ( u -- a 0 | err )
var fit = searchfit(tos) ;
if (fit<0) {
s[++sp] = newchunk(tos) ;
} else {
s[++sp] = splitchunk(fit,tos) ;
}
tos = 0 ;
}
primitive("allocate",forthallocate) ;
describe("u -- a 0 | err",ans|jsf) ;
function forthfree() { // ( a -- 0 | err )
var temp = Math.min(m[tos-2],nusedchunks-1) ;
var chunkaddr = usedchunk[temp] ;
if (chunkaddr != tos) {
throwerror(-72) ;
} else {
freechunk[nfreechunks++] = chunkaddr ;
nusedchunks-- ;
var lastchunk = usedchunk.pop() ;
if (temp < nusedchunks) {
m[lastchunk-2] = temp ;
usedchunk[temp] = lastchunk ;
}
}
freechunk.sort()
chunkaddr = freechunk[0] + m[freechunk[0]-1] + 2;
// combining from end of memory towards lower addresses may be quicker .
for (temp = 1 ; temp < nfreechunks ; temp++) {
if (freechunk[temp] == chunkaddr) { // merge chunks
chunksize = m[freechunk[temp]-1] + 2 ;
m[freechunk[temp-1]-1] += chunksize ;
chunkaddr += chunksize ;
nfreechunks-- ;
for (var i=temp ; i<nfreechunks ; freechunk[i++] = freechunk[i]) ;
freechunk.pop() ;
temp--;
} else {
chunkaddr = freechunk[temp] + m[freechunk[temp]-1] + 2;
}
}
temp = freechunk[nfreechunks-1] ;
if (( temp + m[temp-1]) == heapend ) {
nfreechunks-- ;
heapend = (freechunk.pop() - 2 ) ;
}
tos = 0 ;
}
primitive("free",forthfree) ;
describe("a -- 0 | err",ans|jsf) ;
// RESIZE
// freed areas appendable ?
// yes: append
// no: allocate new, copy
function forthdotallocated() {
type("allocated:") ;
for (var i=0 ; i<nusedchunks ; i++ ) {
cr() ;
type(i + "/" + m[usedchunk[i]-2] + ": " + (usedchunk[i]) + " " + m[usedchunk[i]-1]) ;
}
cr() ; type("freed:") ;
for (i=0 ; i<nfreechunks ; i++ ) {
cr() ;
type(i + ": " + (freechunk[i]) + " " + m[freechunk[i]-1]) ;
}
}
primitive(".allocated",forthdotallocated) ;
describe("--",jsf) ;
// =================================================================================================
// peephole optimizer
// =================================================================================================
// function forthpeephole() { \\ ( xt1 -- xt2 )
// }
// var x_peephole = primitive("peephole",forthpeephole) ;
// describe("xt1 -- xt2",jsf) ;
// =================================================================================================
// utility
// =================================================================================================
definitions(forth) ;
function forthbye() {
forthsavebuffers();
window.close() ;
}
primitive("bye",forthbye) ;
describe("--",any|foerthchen) ;
function forthdecimal() { m[base] = 10 ; }
var x_decimal = primitive("decimal",forthdecimal) ;
describe("--",any) ;
function forthhex() { m[base] = 16 ; }
var x_hex = primitive("hex",forthhex) ;
describe("--",any) ;
// ( a n -- ) execute as javascript
function fortheval() { forthpack(); eval(tos) ; tos=s[sp--]; }
var x_eval = primitive("eval",fortheval)
describe("a n --",jsf) ;
// ----------- javascript popup dialogs ------------
// pops up an alert
function forthalert() { // ( a n -- )
forthpack() ;
alert(tos) ;
tos = s[sp--] ;
}
primitive("alert",forthalert) ;
describe("a n --",jsf) ;
// pops up a confirm window
function forthconfirm() { // ( a n -- f )
forthpack() ;
tos = -confirm(tos) ;
}
primitive("confirm",forthconfirm) ;
describe("a n -- d",jsf) ;
function forthenter() { // ( a1 n1 a2 -- n2 )
tos = unpackstring(prompt(pack(s[sp-1],s[sp])),tos) ;
sp -= 2 ;
}
primitive("enter",forthenter) ;
describe("a1 n1 a2 -- n2",jsf) ;
// --------------- time ----------------
function forthms() {
suspended = w ;
setTimeout(function() { virtualmachine(ip) ; }, tos) ;
tos = s[sp--] ;
}
var x_ms = primitive("ms",forthms) ;
describe("u --",jsf) ;
function forthepoch() { // ( -- u )
s[++sp] = tos ;
w = new Date().getTime() ;
tos = Math.floor(w/1000) ;
}
primitive("epoch",forthepoch)
describe("-- u",jsf) ;
// ------------- random ---------------
function forthrandom() {
tos = Math.floor(Math.random() * tos) ;
}
primitive("random",forthrandom) ;
describe("u1 -- u2",jsf)
// --------- helpers for see -----------
definitions(hidden) ;
// where is source ? -1:console -2: script 0..: blk*1024+charpos
function forthlocate() { tos = src[tos] ; } // ( xt -- n )
primitive("locate",forthlocate) ;
describe("xt -- n",jsf) ;
// fails with does> words
function forthwordtype() { // ( xt1 -- xt2 )
if (tos <= primitives) {
tos = 0 ; // primitive
} else {
tos = m[x[tos]] ; // other
}
}
primitive("wordtype",forthwordtype) ;
describe("xt1 -- xt2",jsf) ;
// returns source of a primitive
function forthdisassemble() { // ( xt a -- n )
var temp = (x[s[sp--]]) + " " ;
tos = unpackstring(temp,tos) ;
}
primitive("disassemble",forthdisassemble) ;
describe("xt a -- n",jsf) ;
definitions(forth) ;
// ----- info screen tools -----
function infosall() { /* No-op. */ } ; primitive("all",infosall) ;
describe("--",jsf) ;
function infostail() { /* No-op. */ } ; primitive("tail",infostail) ;
describe("--",jsf) ;
function setinfoslines() {
infolines = tos ;
info("* buffer size set to " + tos + " lines.") ;
tos = s[sp--] ;
}
primitive("infolines",setinfoslines) ;
describe("u --",jsf) ;
// --------------------------------------
function forthloadhelp() { // ( a n -- )
var temp = "docs/jsforth.html" + "#" + pack(s[sp],tos);
window.frames['help'].window.location.replace(temp.toUpperCase()) ;
sp-- ;
tos = s[sp--] ;
}
var x_loadhelp = primitive("loadhelp",forthloadhelp) ;
// =================================================================================================
// =================================================================================================
// =================================================================================================
// =================================================================================================
// =================================================================================================
// no more primitives below this point
// =================================================================================================
// =================================================================================================
// =================================================================================================
// =================================================================================================
// =================================================================================================
var primitives = wc ;
// =================================================================================================
// builders for non-primitive words
// =================================================================================================
// could speed this up with proper linkage code in t[wc]
function constant(name,value) {
newheader(name,smudgebit) ;
comma(x_doconst) ;
comma(value) ;
t[wc] = nextconstant ;
return wc ;
}
function variable(name) {
newheader(name,smudgebit);
comma(x_dovar);
comma(0);
t[wc] = nextvariable ;
return wc;
}
function colon(name,flags) {
newheader(name,flags|smudgebit);
comma(x_nest);
t[wc] = nexthilevel ;
return wc;
}
function alias(name,flags) {
newheader(name,flags|smudgebit);
x[wc] = x[wc-1] ;
t[wc] = t[wc-1] ;
return wc;
}
function semicolon() { jscomma(x_unnest) }
// =================================================================================================
// control flow for using in this script
// =================================================================================================
function IF() { m[dp++] = x_0branch ; s[++sp] = tos ; tos = dp ; dp++ ; }
function ELSE() { m[dp++] = x_branch ; s[++sp] = dp ; dp++ ; m[tos] = dp-tos ; tos = s[sp--] ; }
function THEN() { m[tos] = dp-tos ; tos = s[sp--] ; }
function BEGIN() { s[++sp] = tos ; tos = dp ; }
function UNTIL() { m[dp++] = x_0branch ; m[dp] = tos-dp++ ; tos = s[sp--]; }
function WHILE() { IF() ; }
function REPEAT() { m[dp++] = x_branch ; m[dp] = s[sp--]-dp++ ; m[tos] = dp-tos ; tos = s[sp--]; }
function AGAIN() { m[dp++] = x_branch ; m[dp] = tos-dp++ ; tos = s[sp--]; }
function makeDO(xt) { m[dp++] = xt; s[++sp] = m[innerloop]; m[innerloop] = dp; s[++sp] = dp ; dp++ ; }
function DO() { makeDO(x_brdo) ; }
function QDO() { makeDO(x_brqdo) ; }
function LOOP() { m[dp++] = x_brloop; m[dp++] = s[sp]+2-dp; m[s[sp]] = dp-s[sp--]; m[innerloop] = s[sp--]; }
function LEAVE() { m[dp++] = x_brleave ; m[dp++] = m[innerloop] ; }
function QLEAVE() { m[dp++] = x_brqleave ; m[dp++] = m[innerloop] ; }
// =================================================================================================
// forth-visible constants and variables
// =================================================================================================
definitions(hidden) ;
var x_innerloop = constant("innerloop",innerloop) ;
var x_innercase = constant("innercase",innercase) ;
definitions(forth) ;
var x_minus1 = constant("-1",-1) ; describe("-- -1",jsf|foerthchen);
var x_0 = constant("0",0) ; describe("-- 0",any) ;
var x_1 = constant("1",1) ; describe("-- 1",any) ;
constant("cell",1) ; describe("-- u",ans|jsf) ;
var x_2 = constant("2",2) ; describe("-- 2",any) ;
var x_bl = constant("bl",bl); describe("-- c",any) ;
var x_esc = constant("esc",esc) ; describe("-- c",jsf) ;
constant("compliance",compliance) ; describe("-- a",jsf) ;
constant("true",-1) ; describe("-- -1",any) ;
constant("false",0) ; describe("-- 0",any) ;
constant("casesensitive",casesensitive) ; describe("-- a",jsf) ;
constant("warnings",warnings) ; describe("-- a",jsf) ;
constant("debugger",debugging) ; describe("-- a",jsf) ;
var x_xontext = constant("context",context) ; describe("-- a",jsf) ;
var x_current = constant("current",current) ; describe("-- a",jsf) ;
var x_blk = constant("blk",blk) ; describe("-- a",any) ;
var x_scr = constant("scr",scr) ; describe("-- a",any) ;
var x_lastxt = constant("last",lastxt) ; describe("-- a",jsf) ;
var x_base = constant("base",base) ; describe("-- a",any) ;
var x_tib = constant("tib",tib) ; describe("-- a",any) ;
var x_span = constant("span",span) ; describe("-- a",fig|f79|f83|ans) ;
var x_hashtib = constant("#tib",hashtib) ; describe("-- a","obsolete, variable containing #chars in tib",fig|f79|f83|ans) ;
var x_in = constant(">in",toin) ; describe("-- a",any) ;
var x_state = constant("state",state) ; describe("-- a",any) ;
constant("outfile",outfile) ; describe("-- a",jsf) ;
constant("fit",fittype) ; describe("-- a",jsf) ;
constant("c/l",64) ; describe("-- u",jsf) ;
constant("l/s",16) ; describe("-- u",jsf) ;
constant("c/s",1024) ; describe("-- u",jsf) ;
var x_literal = colon("literal",immediate) ;
compile(x_lit,x_lit,x_comma,x_comma) ;
semicolon() ;
describe("x --",any) ;
// =================================================================================================
// errors
// =================================================================================================
definitions(hidden) ;
var x_stackunderflow = colon("underflow") ; compile(x_lit,-4,x_throw) ;
var x_notfound = colon("notfound") ; compile(x_lit,-13,x_throw) ;
definitions(hidden) ;
definitions(forth) ;
var x_abort = colon("abort") ; compile(x_lit,-1,x_throw) ;
describe("--",any) ;
// =================================================================================================
// compilation
// =================================================================================================
var x_qcomp = colon("?comp") ;
compile(x_compiling,x_0equ) ;
IF() ;
compile(x_lit,-14,x_throw) ;
THEN() ;
semicolon() ;
describe("--",jsf) ;
var x_qexec = colon("?exec") ;
compile(x_compiling) ;
IF() ;
compile(x_lit,-64,x_throw) ;
THEN() ;
semicolon() ;
describe("--",jsf) ;
var x_compilecomma = colon("compile,",immediate) ;
compile(x_qcomp,x_comma) ;
semicolon() ;
describe("xt --",any) ;
// =================================================================================================
// strings
// =================================================================================================
definitions(hidden) ;
var x_commastr = colon(",$") ;
compile(x_here,x_over,x_1plus,x_allot,x_movestr);
semicolon()
describe("a n --",jsf) ;
definitions(forth) ;
// # ( <stream> -- ) compile a string from input stream
var x_commaquote = colon(',"');
compile(x_lit,34,x_parse,x_commastr);
semicolon();
describe("--",jsf) ;
// # ( <stream> -- ) compile a string from input stream
var x_commatick = colon(",'");
compile(x_lit,39,x_parse,x_commastr);
semicolon();
describe("--",jsf) ;
function forthscan() { // ( a1 n2 c -- a2 n2 )
var temp = s[sp--] ;
for ( ; temp ; temp--) {
if (m[s[sp]] == tos) break ;
s[sp]++ ;
}
tos = temp ;
}
primitive("scan",forthscan) ;
describe("a1 n2 c -- a2 n2",any) ;
function forthskip() { // ( a1 n2 c -- a2 n2 )
var temp = s[sp--] ;
for ( ; temp ; temp--) {
if (m[s[sp]] != tos) break ;
s[sp]++ ;
}
tos = temp ;
}
primitive("skip",forthskip) ;
describe("a1 n2 c -- a2 n2",any) ;
definitions(hidden) ;
var x_compilestringword = colon('string\",') ;
compile(x_qcomp,x_comma,x_commaquote) ;
semicolon() ;
var x_compiletickstringword = colon("string',") ;
compile(x_qcomp,x_comma,x_commatick) ;
semicolon() ;
definitions(forth) ;
var x_squote = colon('s"',immediate) ;
compile(x_lit,x_brsquote,x_compilestringword);
semicolon();
describe("--",any) ;
var x_cquote = colon('c"',immediate);
compile(x_lit,x_brcquote,x_compilestringword);
semicolon();
describe("--",ans|jsf) ;
var x_dotquote = colon('."',immediate);
compile(x_lit,x_brdotquote,x_compilestringword);
semicolon();
describe("--",any|foerthchen) ;
colon("s'",immediate) ;
compile(x_lit,x_brsquote,x_compiletickstringword);
semicolon();
describe("--",any) ;
colon(".'",immediate);
compile(x_lit,x_brdotquote,x_compiletickstringword);
semicolon();
describe("--",any|foerthchen) ;
var x_dumul = colon("du*") // ( ud1 u -- ud2 )
compile(x_tuck,x_2tor,x_ummul,x_0,x_2rfrom,x_mul,x_dplus)
semicolon() ;
colon(">number") ;
compile(x_2dup,x_plus,x_tor);
compile(x_0) ;
QDO() ;
compile(x_count,x_digit,x_dup,x_0less) ;
IF() ;
compile(x_drop,x_1minus) ;
LEAVE() ;
THEN() ;
compile(x_swap,x_tor,x_tor);
compile(x_base,x_fetch,x_dumul);
compile(x_rfrom,x_0,x_dplus);
compile(x_rfrom) ;
LOOP() ;
compile(x_rfrom,x_over,x_minus);
semicolon() ;
describe("ud1 a1 u1 -- ud2 a2 u2",ans|jsf)
// function forthtonumber() { // ( ud1 a1 u1 -- ud2 a2 u2 )
// var digit ;
// var radix = m[base] ;
// w = s[sp] ;
// for ( ; tos ; tos-- ) {
// digit = m[w] - 48 ;
// if ( digit > 16 ) digit -= 7 ;
// if ( digit > 36 ) digit -= 32 ;
// if ( (digit >= 0) && (digit < radix) ) {
// s[sp-2] *= radix ;
// s[sp-2] += digit ;
// w++ ;
// } else {
// s[sp] = w ;
// break ;
// }
// }
// }
// primitive(">number",forthtonumber) ;
// describe("d1 a1 n1 -- d2 a2 n2",ans|jsf) ;
var x_abortquote = colon('abort"',immediate);
compile(x_lit,x_brabortquote,x_compilestringword);
semicolon();
describe("--",any) ;
// =================================================================================================
// defining words
// =================================================================================================
// ( a <stream> -- )
var x_create = colon("create") ; compile(x_lit,x_dovar,x_use,x_reveal) ; semicolon() ;
describe("--",any) ;
var x_const = colon("constant") ;
compile(x_lit,x_doconst,x_use,x_comma,x_reveal) ; // which is left in here for the moment. doesn't hurt.
semicolon() ;
describe("x --",any) ;
colon("fconstant") ; compile(x_lit,x_dofconst,x_use,x_fcomma,x_reveal) ; semicolon() ;
describe("r -- ) ( -- r )",ans|jsf) ;
colon("value") ; compile(x_lit,x_dovalue,x_use,x_comma,x_reveal) ; semicolon() ;
describe("x --",ans|jsf) ;
colon("variable") ; compile(x_create,x_0,x_comma) ; semicolon() ;
describe("--",any) ;
alias("fvariable") ;
describe("-- ) ( -- a",any) ;
colon(";",immediate) ; compile(x_lit,x_unnest,x_comma,x_bropen,x_reveal) ; semicolon() ;
describe("--",any|foerthchen) ;
colon(":") ; compile(x_lit,x_nest,x_use,x_brclose) ; semicolon() ;
describe("<wordname> --",any|foerthchen) ;
colon("does>",immediate) ;
compile(x_lit,x_setdoes,x_compilecomma) ;
compile(x_lit,x_unnest,x_compilecomma) ;
semicolon() ;
describe("--",any) ;
// =================================================================================================
// i/o
// =================================================================================================
var x_keyq = colon("key?") ; compile(x_key1query,x_key2query) ; semicolon() ;
describe("-- f",jsf) ;
colon("?terminal") ; compile(x_keyq) ; semicolon() ;
describe("-- f",fig|f79) ;
var x_key = colon("key") ; compile(x_key1,x_key2) ; semicolon() ;
describe("-- c",any) ;
var x_word = colon("word") ;
compile(x_parse,x_here,x_movestr,x_here) ;
semicolon() ;
describe("c -- a",any|foerthchen) ;
var x_accept = colon("accept") ; // ( a n1 -- n2 )
compile(x_over,x_swap,x_1plus) ;
BEGIN() ;
compile(x_qdup) ;
WHILE() ;
compile(x_key,x_decode) ;
REPEAT() ;
compile(x_swap,x_minus) ;
semicolon() ;
describe("a n1 -- n2",ans|jsf) ;
colon("expect")
compile(x_accept,x_span,x_store) ;
semicolon() ;
describe("a n --",fig|f79|f83|ans) ;
var x_query = colon("query") ;
compile(x_tib,x_dup,x_lit,tibsize,x_accept) ;
compile(x_dup,x_hashtib,x_store,x_storesource) ;
compile(x_in,x_off) ;
semicolon() ;
describe("--",any) ;
var x_sbr = colon("s(") ;
compile(x_lit,41,x_parse) ;
semicolon() ;
describe("-- a n",jsf) ;
colon(".(",immediate) ;
compile(x_sbr,x_type) ;
semicolon() ;
describe("<stream> --",ans|jsf) ;
var x_char = colon("char",immediate) ; // char
compile(x_bl,x_parse,x_drop,x_cfetch);
compile(x_compiling) ;
IF() ;
compile(x_literal) ;
THEN() ;
semicolon() ;
describe("<stream> -- c",ans|jsf) ;
alias("[char]",immediate) ; // [char]
describe("<stream> -- c",ans|jsf) ;
colon("\\",immediate) ;
compile(x_0,x_parse,x_2drop) ;
semicolon() ;
describe("<stream> --",any) ;
colon("(",immediate) ;
compile(x_lit,41,x_parse,x_2drop) ;
semicolon() ;
describe("<stream> --",any) ;
colon("(s",immediate) ;
compile(x_lit,41,x_parse,x_mintrailing,x_storestackeffect) ;
semicolon() ;
describe("<stream> --",any) ;
var x_hash = colon("#") ;
compile(x_base,x_fetch,x_udslashmod,x_rot,x_lit,9,x_over,x_less)
IF() ;
compile(x_lit,39,x_plus) ;
THEN() ;
compile(x_lit,48,x_plus,x_hold) ;
semicolon() ;
describe("d1 -- d2",any) ;
var x_hashs = colon("#s") ;
BEGIN() ;
compile(x_hash,x_2dup,x_or,x_0equ)
UNTIL() ;
semicolon() ;
describe("d1 -- d2",any) ;
var x_parenddot = colon("(d.)") ;
compile(x_dup,x_tor,x_dabs,x_lesshash,x_hashs,x_rfrom,x_sign,x_hashmore,x_type) ;
semicolon() ;
describe("d --",any) ;
var x_ddot = colon("d.") ; // d.
compile(x_parenddot,x_space) ;
semicolon() ;
describe("d --",any) ;
var x_ddotr = colon("d.r") ; // d.r
compile(x_tor) ;
compile(x_dup,x_tor,x_dabs,x_lesshash,x_hashs,x_rfrom,x_sign,x_hashmore) ;
compile(x_rfrom,x_2dup,x_more) ;
IF() ;
BEGIN() ;
compile(x_qdup) ;
WHILE() ;
compile(x_1minus,x_lit,42,x_emit)
REPEAT() ;
compile(x_2drop) ;
ELSE() ;
compile(x_over,x_minus,x_spaces,x_type) ;
THEN() ;
semicolon() ;
describe("d --",any) ;
var x_udot = colon("u.") ; // u.
compile(x_0,x_ddot) ;
semicolon() ;
describe("u --",any) ;
var x_dot = colon(".") ; // .
compile(x_stod,x_ddot) ;
semicolon() ;
describe("n --",any) ;
colon("(.)") ;
compile(x_stod,x_parenddot) ;
semicolon() ;
describe("n --",foerthchen) ;
colon("u.r") ; // u.r ( u1 u2 -- )
compile(x_0,x_swap,x_ddotr) ;
semicolon() ;
describe("u1 u2 --",any) ;
var x_dotr = colon(".r") ; // .r ( n u -- )
compile(x_tor,x_stod,x_rfrom,x_ddotr) ;
semicolon() ;
describe("n u --",any) ;
// =================================================================================================
// flow control
// =================================================================================================
definitions(hidden) ;
var x_structured = colon("structured") ;
compile(x_2dup,x_nequ) ;
IF() ;
compile(x_unstructured)
THEN() ;
compile(x_2drop) ;
semicolon() ;
var x_resolve = colon("resolve") ;
compile(x_here,x_minus,x_comma) ;
semicolon() ;
var x_resolveback = colon("<resolve") ;
compile(x_here,x_over,x_minus,x_swap,x_store) ;
semicolon() ;
var x_qclause = colon("?clause") ;
compile(x_lit,x_0branch,x_comma) ;
semicolon() ;
var x_clause = colon("clause") ;
compile(x_lit,x_branch,x_comma) ;
semicolon() ;
var x_mark = colon("mark") ;
compile(x_here,x_0,x_comma) ;
semicolon() ;
definitions(forth) ;
var x_for = colon("for",immediate) ;
compile(x_qcomp,x_lit,x_brfor,x_comma) ;
compile(x_here,x_innerloop,x_exchange) ;
compile(x_here,x_0,x_comma) ;
compile(x_lit,6) ;
semicolon() ;
describe("n --",jsf) ;
var x_next = colon("next",immediate) ;
compile(x_qcomp,x_lit,6,x_structured) ;
compile(x_lit,x_brnext,x_comma) ;
compile(x_dup,x_1plus,x_resolve) ;
compile(x_resolveback,x_innerloop,x_store) ;
semicolon() ;
describe("--",jsf) ;
var x_if = colon("if",immediate) ;
compile(x_qcomp,x_qclause,x_mark,x_1) ;
semicolon() ;
describe("f --",any) ;
var x_else = colon("else",immediate) ;
compile(x_qcomp,x_1,x_structured,x_clause,x_mark) ;
compile(x_swap,x_resolveback,x_2) ;
semicolon() ;
describe("--",any) ;
var x_then = colon("then",immediate) ;
compile(x_qcomp,x_dup,x_2,x_equ,x_plus) ;
compile(x_1,x_structured,x_resolveback) ;
semicolon() ;
describe("--",any) ;
alias("endif",immediate) ;
describe("-- ) ( --",jsf) ;
var x_begin = colon("begin",immediate) ;
compile(x_qcomp,x_here,x_lit,3) ;
semicolon() ;
describe("--",any) ;
var x_while = colon("while",immediate) ;
compile(x_qcomp,x_lit,3,x_structured) ;
compile(x_qclause,x_mark,x_lit,4) ;
semicolon() ;
describe("f --",any) ;
var x_repeat = colon("repeat",immediate) ;
compile(x_qcomp,x_lit,4,x_structured) ;
compile(x_swap,x_clause,x_resolve) ;
compile(x_resolveback) ;
semicolon() ;
describe("--",any) ;
var x_again = colon("again",immediate) ;
compile(x_qcomp,x_lit,3,x_structured,x_clause,x_resolve) ;
semicolon() ;
describe("--",any) ;
var x_until = colon("until",immediate) ;
compile(x_qcomp,x_lit,3,x_structured,x_qclause,x_resolve) ;
semicolon() ;
describe("f --",any) ;
var x_do = colon("do",immediate)
compile(x_qcomp,x_lit,x_brdo,x_comma) ;
compile(x_here,x_innerloop,x_exchange) ;
compile(x_here,x_0,x_comma) ;
compile(x_lit,5) ;
semicolon() ;
describe("x1 x2 --",any) ;
var x_qdo = colon("?do",immediate)
compile(x_qcomp,x_lit,x_brqdo,x_comma) ;
compile(x_here,x_innerloop,x_exchange) ;
compile(x_here,x_0,x_comma) ;
compile(x_lit,5) ;
semicolon() ;
describe("x1 x2 --",any) ;
var x_loop = colon("loop",immediate)
compile(x_qcomp,x_lit,5,x_structured) ;
compile(x_lit,x_brloop,x_comma) ;
compile(x_dup,x_1plus,x_resolve) ;
compile(x_resolveback);
compile(x_innerloop,x_store) ;
semicolon() ;
describe("--",any) ;
var x_plusloop = colon("+loop",immediate) ;
compile(x_qcomp,x_lit,5,x_structured) ;
compile(x_lit,x_brplusloop,x_comma) ;
compile(x_dup,x_1plus,x_resolve) ;
compile(x_resolveback) ;
compile(x_innerloop,x_store) ;
semicolon() ;
describe("n --",any) ;
definitions(hidden) ;
var x_leavecomma = colon("leave,") ;
compile(x_qcomp,x_innerloop,x_fetch,x_qdup,x_0equ) ;
IF() ;
compile(x_lit,-26,x_throw) ;
THEN() ;
compile(x_swap,x_comma,x_comma) ;
semicolon() ;
describe("xt --",any) ;
definitions(forth) ;
// fig/f79 leave is different from later leave:
// leaving loop was only done when loop was reached,
// statements between leave and loop were still executed.
colon("leave",immediate) ;
compile(x_lit,x_brleave79,x_comma) ;
semicolon() ;
describe("--",f79|fig) ;
var x_leave = colon("leave",immediate) ;
compile(x_lit,x_brleave,x_leavecomma) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
var x_qleave = colon("?leave",immediate) ;
compile(x_lit,x_brqleave,x_leavecomma) ;
semicolon() ;
describe("f --",jsf) ;
colon("unloop",immediate) ;
compile(x_qcomp,x_innerloop,x_fetch,x_0equ) ;
IF() ;
compile(x_lit,-26,x_throw) ;
THEN() ;
compile(x_lit,x_brunloop,x_comma,x_unnest) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
// structure check is still limited.
// doesn't complain when of .. endof is used outside of case .. endcase
colon("case",immediate) ;
compile(x_qcomp) ;
compile(x_0,x_innercase,x_exchange) ;
compile(x_lit,7) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
colon("of",immediate) ;
compile(x_qcomp) ;
compile(x_lit,x_brof,x_comma,x_mark) ;
compile(x_1,x_innercase,x_plusstore) ;
compile(x_lit,8) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
colon("endof",immediate) ;
compile(x_qcomp,x_lit,8,x_structured) ;
compile(x_clause,x_mark) ;
compile(x_swap,x_resolveback) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
colon("endcase",immediate) ;
compile(x_qcomp) ;
compile(x_lit,x_drop,x_comma) ;
compile(x_innercase,x_fetch) ;
BEGIN() ;
compile(x_qdup)
WHILE() ;
compile(x_1minus,x_swap,x_resolveback) ;
REPEAT() ;
compile(x_lit,7,x_structured) ;
compile(x_innercase,x_store) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
// =================================================================================================
// dictionary + compiling
// =================================================================================================
definitions(forth) ;
var x_tick = colon("'") ;
compile(x_bl,x_parse,x_search,x_qdup,x_0equ) ;
IF() ;
compile(x_notfound) ;
THEN() ;
semicolon() ;
describe("<stream> -- xt",ans|f83|jsf) ;
colon("'") ;
compile(x_tick,x_tobody) ;
semicolon() ;
describe("<stream> -- a",fig|f79) ;
var x_brtick = colon("[']",immediate) ;
compile(x_tick,x_literal) ;
semicolon() ;
describe("-- a",any) ;
colon("[compile]",immediate) ;
compile(x_tick,x_comma) ;
semicolon() ;
describe("--",any) ;
colon("recurse",immediate) ;
compile(x_lastxt,x_fetch,x_comma) ;
semicolon() ;
describe("--",ans|f83|jsf) ;
colon("to",immediate)
compile(x_tick,x_tobody,x_dup,x_1minus,x_fetch,x_lit,x_dovalue,x_nequ,x_lit,-67,x_and,x_throw) ;
compile(x_compiling) ;
IF() ;
compile(x_lit,x_brto,x_comma,x_comma) ;
ELSE() ;
compile(x_store) ;
THEN() ;
semicolon() ;
describe("<stream> x --",ans|jsf) ;
// =================================================================================================
// interpreter
// =================================================================================================
definitions(hidden);
var x_interpret = colon("interpret") ; // ( -- )
BEGIN() ;
compile(x_bl,x_parse,x_dup) ;
WHILE() ;
compile(x_2dup,x_search,x_qdup) ;
IF() ;
compile(x_nip,x_nip,x_dup,x_qimm) ;
IF() ;
compile(x_execute) ;
ELSE() ;
compile(x_compiling) ;
IF() ;
compile(x_comma) ;
ELSE() ;
compile(x_execute) ;
THEN() ;
THEN() ;
compile(x_depth,x_0less) ;
IF() ;
compile(x_stackunderflow) ;
THEN() ;
ELSE() ;
compile(x_interpretnumber,x_0equ) ;
IF() ;
compile(x_notfound);
THEN() ;
THEN() ;
REPEAT() ;
compile(x_2drop) ;
semicolon();
describe("--",jsf) ;
definitions(forth) ;
var x_evaluate = colon("evaluate") ; // ( a n -- )
compile(x_pushsource) ;
compile(x_in,x_off) ;
compile(x_storesource);
compile(x_interpret) ;
compile(x_popsource) ;
semicolon() ;
describe("a n --",ans|jsf) ;
var x_load = colon("load") ;
compile(x_dup,x_blk,x_exchange,x_tor) ;
compile(x_block,x_lit,1024,x_evaluate) ;
compile(x_rfrom,x_dup,x_blk,x_store) ;
compile(x_dup,x_0less,x_0equ)
IF() ;
compile(x_dup,x_block,x_lit,1024,x_storesource) ;
THEN() ;
compile(x_drop) ;
semicolon() ;
describe("u --",any)
var x_screen = colon("screen") ;
compile(x_scr,x_fetch,x_block) ;
semicolon() ;
describe("-- a",jsf) ;
var x_dotline = colon(".line") ;
compile(x_lit,64,x_mul,x_screen,x_plus,x_lit,64,x_mintrailing,x_type) ;
semicolon() ;
describe("u --",jsf) ;
var x_plusload = colon("+load") ;
compile(x_blk,x_fetch,x_plus,x_load) ;
semicolon() ;
describe("u --",any) ;
colon("thru") ;
compile(x_1plus,x_swap) ;
QDO() ;
compile(x_i,x_load) ;
LOOP();
semicolon() ;
describe("u1 u2 --",any) ;
colon("+thru") ;
compile(x_1plus,x_swap) ;
QDO() ;
compile(x_i,x_plusload) ;
LOOP();
semicolon() ;
describe("u1 u2 --",any) ;
var x_l = colon("l") ;
compile(x_lit,16,x_0) ;
DO() ;
compile(x_cr,x_i,x_2,x_dotr,x_lit,124,x_emit,x_i,x_dotline) ;
LOOP() ;
semicolon() ;
describe("--",jsf) ;
colon("list") ;
compile(x_scr,x_store,x_l) ;
semicolon() ;
describe("u --",any) ;
colon("blank") ;
compile(x_bl,x_fill) ;
semicolon() ;
describe("a u --",any) ;
// =================================================================================================
// utility
// =================================================================================================
colon("help") ;
compile(x_bl,x_parse,x_loadhelp) ;
semicolon() ;
definitions(teststuff) ;
var x_x = colon("x") ; // execute rest of line as javscript
compile(x_0,x_parse,x_eval) ;
semicolon() ;
describe("<stream> --",jsf) ;
var x_jsconsole = colon("") ;
BEGIN() ;
compile(x_cr,x_lit,62,x_emit,x_query,x_x) ;
AGAIN() ;
semicolon() ;
colon("js") ; // javascript console
BEGIN() ;
compile(x_lit,x_jsconsole,x_catch,x_drop) ;
AGAIN() ;
semicolon() ;
describe("--",jsf) ;
// =================================================================================================
// interpreter entry points
// =================================================================================================
definitions(forth) ;
var x_quit = colon("quit") ;
BEGIN() ;
compile(x_query,x_source,x_qdup)
IF() ;
compile(x_evaluate) ;
compile(x_0) ;
THEN() ;
compile(x_drop,x_prompt) ;
AGAIN() ;
describe("??? --",any) ;
semicolon() ;
var x_warm = colon("warm") ; compile(x_warminit,x_quit) ;
describe("??? --",jsf) ;
definitions(hidden) ;
var x_error = colon("error") ;
compile(x_throw) ;
describe("??? n --",jsf) ;
definitions(forth) ;
var warm = dp ; comma(x_warm) ; // called with virtualmachine(warm)
var error = dp ; comma(x_error) ; // called from javascript onError
function virtualmachine(entrypoint) {
suspended = 0 ;
ip=entrypoint ;
do {
w=m[ip++] ; // read next xt from address list
t[w](); // execute
} while (!suspended) ;
}
// =================================================================================================
// jsrepl helpers
// =================================================================================================
function _init() {
virtualmachine(warm);
}
function _run(str) {
for (var i = 0; i < str.length; i++) {
var chr = str.charCodeAt(i);
inbuf.push(chr === 10 ? 13 : chr);
}
inbuf.push(carriagereturn);
virtualmachine(ip);
}
function _stacktop(elementCount) {
// Must be called during execution.
var buffer = [];
s[++sp] = tos;
for (var i = 1; i < sp && i <= elementCount; i++) {
buffer.push(s[sp - i + 1].toString(m[base]));
}
sp-- ;
return buffer.reverse();
}
function _input(callback) {
// Nothing.
}
definitions(forth) ;
function _finish() {
console.log('finished.');
}
primitive("_finish", function() { _finish(); }) ;
describe("--", jsf);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment