Last active
December 26, 2015 02:28
-
-
Save jonasbits/7078237 to your computer and use it in GitHub Desktop.
I want to make this forth simulator take bitcoin OP commands
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
@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